Xor-sequences CodeForces - 691E
题意:在有n个数的数列中选k个数(可以重复选,可以不按顺序)形成一个数列,使得任意相邻两个数异或的结果转换成二进制后其中1的个数是三的倍数。求可能形成的不同数列个数(只要选出的数列中,任意两个元素在原序列中的位置不同,就算作不同的序列,比如在原数列[1,1]中选1个,那么第一个1和第二个1要分开算)。
方法:
很容易列出dp方程:
dp[k][i]表示取了k个,最后一个在第i位。a[i][j]表示i和j异或结果转换成二进制后1的个数是否是3的倍数,1表示是,0表示否。
$dp[k][i]=dp[k-1][1]*a[1][i]+...dp[k-1][n]*a[n][i]$
注意,不是$dp[k][i]=dp[k-1][1]*a[1][i]+...+dp[k-1][i-1]*a[i-1][i]$(这道题是可以重复、不按顺序选的,这么写就是不重复、按顺序)
那么,这样的算法复杂度就是O(nk),太慢了,需要优化。
从小数据开始:
n=3时: dp[1][1]=1 dp[1][2]=1 dp[1][3]=1 dp[2][1]=dp[1][1]*a[1][1]+dp[1][2]*a[2][1]+dp[1][3]*a[3][1] dp[2][2]=dp[1][1]*a[1][2]+dp[1][2]*a[2][2]+dp[1][3]*a[3][2] dp[2][3]=dp[1][1]*a[1][3]+dp[1][2]*a[2][3]+dp[1][3]*a[3][3] dp[3][1]=dp[2][1]*a[1][1]+dp[2][2]*a[2][1]+dp[2][3]*a[3][1] dp[3][2]=dp[2][1]*a[1][2]+dp[2][2]*a[2][2]+dp[2][3]*a[3][2] dp[3][3]=dp[2][1]*a[1][3]+dp[2][2]*a[2][3]+dp[2][3]*a[3][3] 很容易可以发现: 矩阵1 dp[1][1] dp[1][2] dp[1][3] 矩阵2 a[1][1] a[1][2] a[1][3] a[2][1] a[2][2] a[2][3] a[3][1] a[3][2] a[3][3] 矩阵1*矩阵2 dp[2][1] dp[2][2] dp[2][3]
更大的数据以此类推,因此很容易想到用矩阵快速幂优化。
而要求dp[k][],就要由dp[1][]乘k-1次矩阵2,可以改为算出来矩阵2的k-1次幂放入矩阵3,再将dp[1][]乘上矩阵3,得到的就是dp[k][]。最终答案就是dp[k][1]+..+dp[k][n]。
所以说...这个矩阵快速幂的题..居然不用自己去构造转移矩阵??
另外:
__builtin_popcountll:参照__builtin_popcount,那个是针对long整型的,这个是针对long long的
还有手动写的
1 #include<cstdio> 2 #include<cstring> 3 #define md 1000000007 4 typedef long long LL; 5 LL n,k,anss; 6 LL a[101]; 7 struct Mat 8 { 9 LL data[101][101],x,y; 10 Mat() 11 { 12 memset(data,0,sizeof(data)); 13 x=y=0; 14 } 15 Mat operator*(const Mat& b) 16 { 17 Mat temp; 18 LL i,j,k; 19 for(i=1;i<=x;i++) 20 for(j=1;j<=b.y;j++) 21 for(k=1;k<=y;k++) 22 temp.data[i][j]=(data[i][k]*b.data[k][j]+temp.data[i][j])%md; 23 temp.x=x; 24 temp.y=b.y; 25 return temp; 26 } 27 Mat& operator*=(const Mat& b) 28 { 29 return (*this)=(*this)*b; 30 } 31 Mat& operator=(const Mat& b) 32 { 33 memcpy(data,b.data,sizeof(data)); 34 x=b.x; 35 y=b.y; 36 return *this; 37 } 38 }ma,o,bbb,ccc; 39 Mat pow(const Mat& a,LL b) 40 { 41 Mat ans=o; 42 if(b==0) return ans; 43 Mat base=a; 44 while(b!=0) 45 { 46 if(b&1!=0) ans*=base; 47 base*=base; 48 b>>=1; 49 } 50 return ans; 51 } 52 int main() 53 { 54 LL i,j; 55 scanf("%I64d%I64d",&n,&k); 56 for(i=1;i<=n;i++) 57 scanf("%I64d",&a[i]); 58 ma.x=ma.y=n; 59 for(i=1;i<=n;i++) 60 for(j=1;j<=n;j++) 61 ma.data[i][j]=(__builtin_popcountll(a[i]^a[j])%3==0); 62 o.x=o.y=n; 63 for(i=1;i<=n;i++) 64 for(j=1;j<=n;j++) 65 o.data[i][j]=(i==j); 66 bbb=pow(ma,k-1); 67 ccc.x=1;ccc.y=n; 68 for(i=1;i<=n;i++) 69 ccc.data[1][i]=1; 70 ccc*=bbb; 71 for(i=1;i<=n;i++) 72 anss=(anss+ccc.data[1][i])%md; 73 printf("%I64d",anss); 74 return 0; 75 }