bzoj 1411 [ZJOI2009]硬币游戏
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1411 [ZJOI2009]硬币游戏相关的知识,希望对你有一定的参考价值。
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1411
【题意】
N个硬币放在一个有2*N个位置的圆桌上,求T次操作后的情况。对于一个操作,如果两边都是正或都是负,则在中间放一个负,否则放一个正。
【思路】
把正设为0,负设为1,则一个硬币的状态为两边硬币的抑或。
把两次操作看作一次,则一次操作后硬币只有状态发生改变而位置不会改变。
通过数学归纳法得到:一个硬币的状态在操作2^k后是其左右两边与其相距2^k的硬币的抑或。直观的看,就是中间的项都被抑或消掉了。
将T/2进行二进制拆分,不断进行操作即可。最后考虑T的奇偶性。
【代码】
1 #include<cmath> 2 #include<queue> 3 #include<vector> 4 #include<cstdio> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 9 using namespace std; 10 11 typedef long long ll; 12 const int N = 5e5+10; 13 14 ll read() { 15 char c=getchar(); 16 ll f=1,x=0; 17 while(!isdigit(c)) { 18 if(c==‘-‘) f=-1; c=getchar(); 19 } 20 while(isdigit(c)) 21 x=x*10+c-‘0‘,c=getchar(); 22 return x*f; 23 } 24 25 int n; ll m; 26 int a[N],ans[N]; 27 28 int main() 29 { 30 //freopen("in.in","r",stdin); 31 //freopen("out.out","w",stdout); 32 n=read(),m=read(); 33 FOR(i,1,n) ans[i]=read(),ans[i]--; 34 ll x=m/2; 35 for(ll p=1;p<=x;p<<=1) if(x&p) { 36 memcpy(a,ans,sizeof(int)*(n+1)); 37 ll k=p%n; 38 for(int i=1;i<=n;i++) { 39 ll l=(i-1-k+n)%n+1,r=(i-1+k)%n+1; 40 ans[i]=a[l]^a[r]; 41 } 42 } 43 ans[0]=ans[n],ans[n+1]=ans[1]; 44 if(m&1) FOR(i,1,n-1) printf("0 %d ",(ans[i]^ans[i+1])+1); 45 else FOR(i,1,n-1) printf("%d 0 ",ans[i]+1); 46 if(m&1) printf("0 %d",(ans[n]^ans[n+1])+1); 47 else printf("%d 0",ans[n]+1); 48 return 0; 49 }
还能再任性点么 =-=
以上是关于bzoj 1411 [ZJOI2009]硬币游戏的主要内容,如果未能解决你的问题,请参考以下文章