有三我的,分别有\(A,B,C\)块饼干,每次每一个人都会把本身的饼干分红相等的两份而后给其余两我的。当其中有一我的的饼干数量是奇数的时候中止,求会进行几回这样子的操做,或者会永远进行下去。ios
首先无解的状况必定是三个数都是相等的偶数。cookie
不然直接暴力模拟就好了。(盲猜答案不会很大)spa
证实一下答案的范围:不妨令\(A\le B\le C\),那么最大值和最小值之间的差就是\(C-A\),那么执行完一次操做以后最大值和最小值的差变成了\(\frac{C-A}{2}\),这样子以来就能够证实执行次数不会超过\(log\)次了。.net
#include<iostream> #include<cstdio> using namespace std; int a,b,c,ans; int main() { scanf("%d%d%d",&a,&b,&c); if(a%2==0&&a==b&&b==c){puts("-1");return 0;} while(a%2==0&&b%2==0&&c%2==0) { int aa=a>>1,bb=b>>1,cc=c>>1; a=bb+cc;b=aa+cc;c=aa+bb;++ans; } printf("%d\n",ans); return 0; }
有一棵树,一开始全部边权都是\(0\),执行\(M\)次操做,每次会把\(a_i\)到\(b_i\)路径上的每一条边的边权所有加\(1\),切最终每一条边的边权都是偶数。判断这样一棵树是否存在。code
对于全部操做随便构建一棵生成树出来进行一下判断就好了。blog
这样对的缘由是由于你随便怎么连对于奇偶性是不改变的。排序
#include<iostream> #include<cstdio> #include<vector> using namespace std; #define MAX 100100 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,m,f[MAX],a[MAX]; int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} vector<int> E[MAX]; void dfs(int u,int ff){for(int v:E[u])if(v!=ff)dfs(v,u),a[u]^=a[v];} int main() { n=read();m=read(); for(int i=1;i<=n;++i)f[i]=i; for(int i=1;i<=m;++i) { int u=read(),v=read(); if(getf(u)!=getf(v)) E[u].push_back(v),E[v].push_back(u),f[getf(u)]=getf(v); a[u]^=1;a[v]^=1; } for(int i=1;i<=n;++i) if(getf(i)!=getf(1))E[1].push_back(i),E[i].push_back(1),f[getf(i)]=getf(1); dfs(1,0); for(int i=1;i<=n;++i)if(a[i]){puts("NO");return 0;} puts("YES"); return 0; }
有一个\(H\times W\)的网格,有些格子不能走。如今有一我的从某个起点开始,进行如下步骤:首先沿着相邻格子走不超过\(k\)步,而后选择不超过\(k\)个不能走的格子让它们变成能走。get
问最少进行上述操做多少次这我的能够走到网格图的边界位置。string
把操做顺序换一下,咱们先走\(k\)次。接下来进行若干轮,每次都是先把\(k\)个格子解锁再走,等价于没有限制了。it
因此只须要预处理先走\(k\)步能够到达的位置再计算一下最短路就行啦。
#include<iostream> #include<cstdio> #include<queue> using namespace std; #define MAX 808 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int ans,n,m,K,sx,sy; char g[MAX][MAX]; int Calc(int x,int y){return min(min(x-1,n-x),min(y-1,m-y));} int dis[MAX][MAX]; int d[4][2]={1,0,0,1,-1,0,0,-1}; void BFS(int sx,int sy) { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)dis[i][j]=1e9; dis[sx][sy]=0;ans=1e9; queue<int> Qx,Qy;Qx.push(sx),Qy.push(sy); while(!Qx.empty()) { int x=Qx.front(),y=Qy.front();Qx.pop();Qy.pop(); ans=min(ans,(Calc(x,y)+K-1)/K); if(dis[x][y]>=K)continue; for(int i=0;i<4;++i) { int xx=x+d[i][0],yy=y+d[i][1]; if(xx<1||xx>n||yy<1||yy>m)continue; if(g[xx][yy]=='#')continue; if(dis[xx][yy]<=dis[x][y]+1)continue; dis[xx][yy]=dis[x][y]+1; Qx.push(xx);Qy.push(yy); } } } int main() { n=read();m=read();K=read(); for(int i=1;i<=n;++i)scanf("%s",g[i]+1); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(g[i][j]=='S')sx=i,sy=j; BFS(sx,sy); printf("%d\n",ans+1); return 0; }
有一棵树,两我的轮流给节点染色,先手染白,后手染黑。
染完以后把全部和黑色节点相邻的点所有染黑。
若是还有白点则先手胜,不然后手胜。
判断胜负状况。
首先发现胜利状况是存在一个白点使得其相邻的点全是白点。
那么,发现若是这棵树存在一个完美匹配的话,那么后手必胜,即先手不管走哪一个位置,后手必定能够走一个匹配的相邻的位置。
不然的话找一个不在匹配内的点做为根节点,这样子它的全部儿子的匹配都在其自身的子树内,这样子直接对于全部儿子染色,此时后手必须染其儿子对应的匹配,此时先手必胜。
#include<iostream> #include<cstdio> #include<vector> using namespace std; #define MAX 100100 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n; vector<int> E[MAX]; bool dfs(int u,int ff) { int cnt=0; for(int v:E[u]) { if(v==ff)continue; if(dfs(v,u))++cnt; } if(cnt>=2){puts("First");exit(0);} return cnt^1; } int main() { n=read(); for(int i=1;i<n;++i) { int u=read(),v=read(); E[u].push_back(v); E[v].push_back(u); } if(dfs(1,0))puts("First"); else puts("Second"); return 0; }
你有一棵树,一开始全部边都是蓝色的。
你要执行\(n-1\)次以下的操做:每次选定一条全是蓝色边的路径,随意断掉其中一条边,而后在两个端点之间连上一条红边。
如今给你由红边组成的树,问你可否从蓝边树变成给定的红边树。
发现最后一次操做的边必定既在蓝树中又在红树中出现,而连完边以后这两个点就能够直接合并在一块儿。
那么咱们每次找到这样一条边,而后把两个集合合并。
那么直接启发式合并处理这个问题就好了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<set> #include<map> using namespace std; #define ll long long #define MAX 100100 #define pi pair<int,int> #define mp make_pair #define fr first #define sd second inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,f[MAX]; int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} queue<pi> Q; map<pi,int> M; set<int> E[MAX]; pi get(int x,int y){if(x>y)swap(x,y);return mp(x,y);} void Link(int x,int y) { E[x].insert(y);E[y].insert(x); pi u=get(x,y); if(++M[u]==2)Q.push(u); } int main() { n=read(); for(int i=1;i<=n;++i)f[i]=i; for(int i=1;i<=n+n-2;++i)Link(read(),read()); for(int i=1,x,y;i<n;++i) { do { if(Q.empty()){puts("NO");return 0;} x=Q.front().fr,y=Q.front().sd;Q.pop(); x=getf(x);y=getf(y); }while(x==y); if(E[x].size()>E[y].size())swap(x,y); f[x]=y;M.erase(get(x,y));E[y].erase(x); for(auto v:E[x]) { int fv=getf(v); if(fv==y)continue; M.erase(get(x,fv)); E[fv].erase(x); Link(fv,y); } } puts("YES"); return 0; }
给定一个排列,把全部是前缀最大值的数直接丢到数列的最后,问多少次这样的操做以后数列会被排好序。
不会.jpg。因此能够开心的照抄___的题解了。
首先发现\(1\)这个东西颇有意思,它并不影响其余元素,即若是\(1\)在开头位置那么就没它的事了,不然它必定不会成为前缀最大值。那么咱们把\(1\)给丢掉,只考虑\([2,n]\)的数量,伪装它的答案是\(T\),那么最终的答案就是\(T\)或者\(T+1\)。首先\(T=0\)的状况特殊处理掉。不然的话考虑进行完\(T-1\)次以后的数列,设\(f\)为数列的第一项,那么\(f>2\),由于若是\(f=2\)的话证实这个序列要么已经排好序了,要么在下一次操做以后\(2\)会被丢到后面,又由于没有排好序,因此确定不能只进行一次就获得最终序列。
这样子的话,进行完下一次操做以后\([2,n]\)就完成了排序,考虑把\(1\)给加入进来,若是数列前三项是\(f,1,2\),那么显然一次操做以后\(1\)也顺带回到了本身的位置,此时答案仍然是\(T\)。不然的话,一次操做以后显然\(1\)尚未归位,须要再进行一次\(1\)才能回到本身的位置上,此时答案是\(T+1\)。
而后我就不会证了,抄遍代码就滚粗了。
#include<iostream> #include<cstdio> using namespace std; #define MAX 200200 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,a[MAX],b[MAX],T[MAX],f[MAX]; int main() { n=read(); for(int i=1;i<=n;++i)b[a[i]=read()]=i; for(int i=n-1;i;--i) if(!T[i+1]) { if(b[i]>b[i+1])T[i]=1,f[i]=i+1; else T[i]=0; } else { if((b[f[i+1]]<b[i])+(b[i]<b[i+1])+(b[i+1]<b[f[i+1]])==2)T[i]=T[i+1],f[i]=f[i+1]; else T[i]=T[i+1]+1,f[i]=i+1; } printf("%d\n",T[1]); return 0; }