bzoj1411: [ZJOI2009]硬币游戏
1411: [ZJOI2009]硬币游戏
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 965 Solved: 420
[Submit][Status][Discuss]
Description
Orez很喜欢玩游戏,他最近发明了一款硬币游戏。他在桌子的边缘上划分出2*n个位置并按顺时针把它们标号为1,2,……,2n,然后把n个硬币放在标号为奇数的位置上。接下来每次按如下操作:在任意两个硬币之间放上一个硬币,然后将原来的硬币拿走;所放硬币的正反面由它两边的两个硬币决定,若两个硬币均为正面朝上或反面朝上,则所放硬币为正面朝上,否则为反面朝上。 那么操作T次之后桌子边缘上硬币的情况会是怎样的呢?
Input
文件的第一行包含两个整数n和T。 接下的一行包含n个整数,表示最开始桌面边缘的硬币摆放情况,第i个整数ai表示第i个硬币摆放在2*i-1个位置上,ai=1表示正面朝上,ai=2表示反面朝上。
Output
文件仅包含一行,为2n个整数,其中第i个整数bi桌面边缘的第i个位置上硬币的情况,bi=1表示正面朝上,bi=2表示反面朝上,bi=0表示没有硬币。
Sample Input
10 5
2 2 2 1 1 1 1 1 1 2
2 2 2 1 1 1 1 1 1 2
Sample Output
0 1 0 1 0 1 0 1 0 2 0 1 0 2 0 1 0 1 0 1
数据范围
30%的数据 n≤1000 T≤1000
100%的数据 n≤100000 T≤2^60
数据范围
30%的数据 n≤1000 T≤1000
100%的数据 n≤100000 T≤2^60
题解:转自http://blog.csdn.net/PoPoQQQ/article/details/39934161?locationNum=6
首先我们令硬币正面为0 反面为1 那么很容易发现新硬币的值为两边硬币的异或值 样例也就很好解释了
1-1-1-0-0-0-0-0-0-1- 0
-0-0-1-0-0-0-0-0-1-0 1
0-0-1-1-0-0-0-0-1-1- 2
-0-1-0-1-0-0-0-1-0-1 3
1-1-1-1-1-0-0-1-1-1- 4
-0-0-0-0-1-0-1-0-0-0 5
然后这题n<=10W 矩阵乘法一定MLE 即使矩阵特殊构造可以干掉一维空间复杂度 O(n^2*logT)的时间也无法承受
我们只考虑偶数的行
易知第二行每个数是原序列该位置左右两个数的异或
由数学归纳法可以 第2^k行每个数是原序列该位置左侧第2^(k-1)个数和右侧第2^(k-1)个数的异或
然后将T进行二进制拆分,每位进行一次变换即可 最后再讨论T的奇偶
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #define ll long long 7 8 using namespace std; 9 10 ll n,t,a[200000],b[200000]; 11 ll f(ll b,ll k) 12 { 13 ll x=b-k,y=b+k; 14 x=(x%(n*2)+n*2-1)%(n*2)+1; 15 y=(y-1)%(n*2)+1; 16 if (k==0) return a[x]; 17 if (a[x]==0) return 0; 18 if (a[x]==a[y]) return 1; 19 else return 2; 20 } 21 void work(ll k,ll q) 22 { 23 if (k==0) return; 24 work(k/2,q*2); 25 if (k%2==1) 26 { 27 memset(b,0,sizeof(b)); 28 for (ll j=1;j<=n*2;j++) 29 b[j]=f(j,q); 30 swap(a,b); 31 } 32 } 33 int main() 34 { 35 scanf("%lld%lld",&n,&t); 36 for (ll i=1;i<=n;i++) 37 scanf("%lld",&a[i*2-1]); 38 39 work(t,1); 40 41 for (ll i=1;i<n*2;i++) 42 printf("%d ",a[i]); 43 printf("%lld\n",a[n*2]); 44 }