题目大意:给定一圈硬币,T次操作,每次操作在每个硬币中间各放一枚硬币,硬币的正反面由它旁边两个决定,两边相同则为正面,两边不相同则为反面,然后将之前的硬币全部撤掉,问T次操作后的硬币序列
T<=2^60,不是260!!!不然这题就成模拟了!!!
首先原题的题目描述压根就是错的,无视就好
然后下面T的数据范围简直坑爹。。。一开始还以为这是模拟题,写了半天发现各种WA,后来看了数据才发现尼玛。。。
最后就是这题尼玛百度上没有题解!!没弄错的话这应该是这题的第一篇题解0.0 看不懂见谅0.0
首先我们令硬币正面为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的奇偶
时间复杂度O(n*logT)
我又沙茶了。。。之前把^写成+,写成|,这次终于写成&了。。。我觉得再过不久我就能把^写成*了。。。
此外这题和杨辉三角的异或形式的分形性有很大关联。。。不懂的自己画个推推就行了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef long long ll; int n,tot; ll m; char a[2][M],ans[M<<1]; int main() { //freopen("coin.in","r",stdin); //freopen("coin.out","w",stdout); int i,x; ll j; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d",&x),a[0][i]=x-1; for(j=2;j<=m;j<<=1) if(m&j) { ++tot; for(i=1;i<=n;i++) { int x=(i+(j>>1)%n+n-1)%n+1; int y=(i-(j>>1)%n+n-1)%n+1; a[tot&1][i]=a[~tot&1][x]^a[~tot&1][y]; } } for(i=1;i<=n;i++) ans[i+i-1]=a[tot&1][i]; if(m&1) { for(i=1;i<=n;i++) ans[i<<1]=ans[i+i-1]^ans[i==n?1:i<<1|1]; for(i=1;i<=n;i++) ans[i+i-1]=-1; } else { for(i=1;i<=n;i++) ans[i+i]=-1; } for(i=1;i<=n<<1;i++) printf("%d%c",ans[i]+1,i==n+n?'\n':' '); }