Xor-sequences CodeForces - 691E || 矩陣快速冪
阿新 • • 發佈:2017-09-30
[1] images temp () const cursor cnblogs 矩陣快速冪 ems
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 }
Xor-sequences CodeForces - 691E || 矩陣快速冪