給你\(A,B,C,D\)四個數字,問你是否存在幾個數相加等於另外幾個數.c++
過於簡單.數組
給你\(n\)個數,每次操做選擇最大的數\(X\),和最小的數\(x\),讓全部最大的數減去一個\(x\).問最後當全部數都相等時的數字爲多少.cookie
能夠發現這個操做至關於求\(\gcd\)的展轉相減法,因而咱們只用求全部數的\(\gcd\)便可.spa
n=rd();int ans=0; for(int i=1; i<=n; ++i) { A[i]=rd(); if(i^1)ans=gcd(A[i],ans); else ans=A[1]; }cout<<ans;
有\(n\)只駱駝,每隻駱駝都有一個重量\(w_i\),它們要通過一座橋.橋被分紅\(m\)段,每段有一個長度\(l_i\)和最大限重\(v_i\),咱們能夠在過橋前安排駱駝的順序,求最遠兩個駱駝相距的最小距離.code
首先暴力枚舉一遍駱駝的先後順序,這時咱們能夠求出任意兩隻駱駝的間的最小距離(預處理一個前綴最大值),而後作一個小\(dp\)就行了.複雜度\(O(n!n^2\log m)\)遊戲
#include<bits/stdc++.h> using namespace std; const int M=1e5+5; int n,m; int w[10],p[10]; int A[10]; struct info { int x,y; bool operator <(const info &_)const { if(y^_.y)return y<_.y; return x<_.x; } }F[M]; int Mx[M],dp[10]; int main(){ n=rd(),m=rd(); for(int i=1; i<=n; ++i)w[i]=rd(),p[i]=i; for(int i=1; i<=m; ++i)F[i].x=rd(),F[i].y=rd(); sort(F+1,F+m+1); for(int i=1; i<=m; ++i) { Mx[i]=F[i].x; if(i>1)Max(Mx[i],Mx[i-1]); } int Ans=1e9; do { for(int i=1; i<=n; ++i)A[p[i]]=w[i],dp[i]=0; for(int i=1; i<=n; ++i) { if(A[i]>F[1].y)return puts("-1"),0; int sum=A[i];dp[i]=dp[i-1]; for(int j=i-1; j; --j) { sum+=A[j]; int p=lower_bound(F+1,F+m+1,(info)<%-1,sum%>)-F-1; if(p)Max(dp[i],dp[j]+Mx[p]); } }Min(Ans,dp[n]); }while(next_permutation(p+1,p+n+1)); printf("%d",Ans); return 0; }
你如今有\(n\)個揹包,\(n\)個盤子,如今揹包\(i\)有\(A[i]\)枚硬幣.如今有\(X\),\(Y\)兩我的在玩遊戲,若是任何一個揹包裏還存在硬幣,那麼當前這我的必須選擇一個揹包,將裏面的全部硬幣倒入任意一個盤子.若是沒有一個揹包還存在硬幣,那麼這我的至少選擇一枚硬幣從一個盤子移出.若是一我的沒法操做,那麼他就輸了.get
能夠看出若是揹包裏的硬幣全轉移到了盤子上,那麼就變成了\(nim\),若異或和爲\(0\),則先手輸,由揹包個數奇偶能夠知道誰會是先手.
若揹包個數爲奇,則第二我的會是先手,能夠發現不管第一我的怎麼操做,總能會使一堆硬幣個數超過\(sum/2\),這樣最後異或和一定不爲\(0\),即第二人必勝.
若揹包個數爲偶(其實跟上面無太大區別),會多一種狀況,就是出現異或和爲\(0\),也就是說咱們須要判斷每種硬幣個數的揹包數爲偶.it
#include<bits/stdc++.h> using namespace std; bool f1; #define LL long long inline LL rd() { LL res=0;bool f=0; char ch; while(ch=getchar(),ch<48||ch>57)if(ch=='-')f=true; do res=(res<<1)+(res<<3)+(ch^48); while(ch=getchar(),ch>47&&ch<58); return f?-res:res; } const int M=1e5+5; int A[M]; bool f2; int main(){ int T=rd(); while(T--) { int n=rd(); for(int i=1; i<=n; ++i)A[i]=rd(); if(n&1){puts("Second");continue;} sort(A+1,A+n+1); bool flag=true; for(int i=1; i<=n; i+=2)if(A[i]!=A[i+1]){puts("First");flag=false;break;} if(flag)puts("Second"); } return 0; }
給你一個\(n\)個節點,\(m\)條邊的無向圖\(G\),若是一個圖爲好圖,那麼它須要知足兩個條件:
1. 節點\(1\)和\(n\)不連通.
2. 沒有重邊和自環.
如今有兩我的\(Taro\),\(Jiro\)玩遊戲,每一個人每一回合能夠在圖\(G\)上連條邊,當一我的的連邊使得圖\(G\)不爲好圖,那麼這我的就輸了.io
歸納一下博弈論:若是我能贏就是敵不動我不動,不然尋找轉折點.
回到此題,首先將原圖縮成若干個聯通塊,對於聯通塊內的點咱們能夠將其連成一個徹底圖,這根本不會影響勝負.
假設咱們只連聯通塊內的邊,若邊數爲奇,則先手贏.
考慮鏈接聯通塊間的邊,思考何時會改變戰局.發現只有將兩個奇數點的聯通塊相連纔會新增偶數條邊,這就是一個轉折點,而新生成的聯通塊點數變成偶數.那麼顯然咱們須要統計奇數點的聯通塊個數\(cnt\).
若\(cnt\)爲奇數,那麼會轉折\(cnt/2\)次.
若\(cnt\)爲偶數,存在一種特殊狀況,可能最後\(1\)和\(n\)所在的聯通塊點數爲奇.咱們須要判斷怎樣纔會產生這種狀況,咱們能夠從奇偶考慮.
當初始時\(1\),\(n\)所在聯通塊點數都爲奇數時,能夠發現前後手均可以扭轉戰局.
當初始時\(1\),\(n\)所在聯通塊點數都爲偶數時,能夠發現前後手都不能夠扭轉戰局.
當初始時\(1\),\(n\)所在聯通塊點數一奇一偶時,只有先手能夠扭轉戰局,也就是說先手必贏.cookies
#include<bits/stdc++.h> using namespace std; const int M=1e5+5; int T; int n,m; int fa[M],Sz[M],A[M]; int find(int g) {return fa[g]==g?g:fa[g]=find(fa[g]);} void Solve(int cur) { if(cur&1)puts("First"); else puts("Second"); } int main(){ T=rd(); while(T--) { n=rd(),m=rd(); for(int i=1; i<=n; ++i)fa[i]=i,Sz[i]=1,A[i]=0; for(int i=1; i<=m; ++i) { int u=rd(),v=rd(); int sx=find(u),sy=find(v); if(sx^sy)A[sy]+=A[sx],fa[sx]=sy,Sz[sy]+=Sz[sx]; A[sy]++; } LL res=0,cnt=0; bool f1=false,f2=false; for(int i=1; i<=n; ++i) if(fa[i]==i) { res+=1LL*(Sz[i]-1)*Sz[i]/2-A[i]; if(Sz[i]&1) { cnt++; if(find(1)==i)f1=true; if(find(n)==i)f2=true; } } if(find(1)==find(n)){puts("Second");continue;} if(res&1) { if(cnt&1)Solve(cnt/2+1); else { if(f1&&f2)Solve(cnt/2); else if(!f1&&!f2)Solve(cnt/2+1); else puts("First"); } }else { if(cnt&1)Solve(cnt/2); else { if(!f1&&!f2)Solve(cnt/2); else if(f1&&f2)Solve(cnt/2+1); else puts("First"); } } } return 0; }
給你一個\(n\)個點,\(m\)條邊的無向連通簡單圖\(G\).你能夠從中選擇邊構造一個新圖\(G_2\),使得這個新圖的點是連通的,而且是個二分圖.詢問選邊的方案數.
徹底不知道該怎麼構造一個二分圖.其實咱們能夠根據它的定義來構造,咱們能夠分開兩組點,使得一組點向另外一組點連邊.若是咱們隨意連邊,咱們沒法保證這張圖是聯通的.
想到先定義一個輔助數組\(f[i]\)表示\(i\)點集組成二分圖但不保證聯通的方案數,顯然求法就是枚舉一組點,將其往另外一組點內隨意連邊,組內不能連邊便可.\(f[i]=\sum_{k\subset i}2^{edge[i]-edge[k]-edge[i\bigoplus k]}\)
對於最終答案咱們也來一個數組\(dp[i]\),容易想到咱們能夠枚舉子集,將不合法的答案算出來最後減去.爲了防止計算重複,咱們能夠先選擇一個點,枚舉的聯通子集都必須包含這個點便可.\(dp[i]=f[i]-\sum_{k\subset i}dp[k]*f[i\bigoplus k]\).
最後答案應該除以\(2\),由於咱們構造二分圖的時候,同一個圖由於染上了不一樣顏色,會計算兩次.
#include<bits/stdc++.h> using namespace std; const int M=1<<17; const int P=998244353; int n,m; int dp[M],f[M]; int edge[M]; int A[M],B[M]; int Pow[M]; bool vis[M]; int main(){ n=rd(),m=rd();Pow[0]=1; for(int i=1; i<=m; ++i)A[i]=rd(),B[i]=rd(); for(int i=1; i<=m; ++i)Pow[i]=Pow[i-1]*2%P; for(int i=0; i<1<<n; ++i) { for(int j=1; j<=m; ++j) if((i&(1<<A[j]-1))&&(i&(1<<B[j]-1)))edge[i]++; f[i]=1; for(int j=i; j; j=(j-1)&i) f[i]=(f[i]+Pow[edge[i]-edge[j]-edge[i^j]])%P; dp[i]=f[i]; int k=i&-i; for(int j=(i-1)&i; j; j=(j-1)&i) if(j&k)dp[i]=(dp[i]-1LL*f[i^j]*dp[j]%P+P)%P; }printf("%d\n",1LL*dp[(1<<n)-1]*(P+1)/2%P); return 0; }