标签:std 快速 递推 str can using 思路 clu mem
题意: 给出红蓝两种,然后排成一个字符串,要求在每一个长度为素数的区间里面是的r(red)的数量不小与b(blue)的数量;
思路:想象当n为2的时候的情况是 rr,rb,br,三种情况,当n为3的时候相当于在后面添加一个b或者r,会发现形成rr的情况是前面rr和br的和,形成br的情况是前面的rb,而形成rb的情况是前面的rr,不能有前面的br形成rb,因为在素数为3的时候不能形成brb;
所以你会发现这个针对的素数只是2和3;
根据递推,设数组a[],b[],c[]分别为后面两个字母为rr,br,rb的字符串的数量,那么可以得到递推式:
a[i] = a[i - 1] + c[i - 1];b[i] = a[i - 1];c[i] = b[i - 1];
而题中要求的是所有的字符串,即s[n] = a[n] + b[n] + c[n];
可以得出s[i] = s[i - 1] + s[i - 3];
n的范围是10^18,那么只能用到矩阵快速幂:[si-3,si-2,si-1]*(0 0 1)=[si-2,si-1,si]
1 0 0
0 1 1
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int mod=1e9+7; 5 6 struct node{ 7 ll a[4][4]; 8 }; 9 int b[6]; 10 node mat; 11 12 13 node jj(node p,node q){ 14 node c; 15 memset(c.a,0,sizeof(c.a)); 16 for(int k = 1; k <= 3; ++k) { 17 for(int i =1; i <=3; ++i) { 18 if(p.a[i][k] <= 0) continue; 19 for(int j = 1; j <=3; ++j) { 20 if(q.a[k][j] <= 0) continue; 21 c.a[i][j] = (c.a[i][j]+p.a[i][k] * q.a[k][j])%mod; 22 } 23 } 24 } 25 return c; 26 } 27 int t; 28 node hh(node p,ll k){ 29 // cout<<t<<endl; 30 node c; 31 for(int i=1;i<=3;i++) 32 for(int j=1;j<=3;j++) c.a[i][j]=(i==j); 33 while(k){ 34 if(k&1) c=jj(c,p); 35 k=k/2; 36 p=jj(p,p); 37 } 38 39 return c; 40 } 41 42 int main(){ 43 scanf("%d",&t); 44 b[1]=2;b[2]=3;b[3]=4;b[4]=6; 45 while(t--){ 46 ll n; 47 scanf("%I64d",&n); 48 if(n<=4) { 49 printf("%d\n",b[n]);continue; 50 } 51 mat.a[1][1]=0;mat.a[1][2]=0;mat.a[1][3]=1; 52 mat.a[2][1]=1;mat.a[2][2]=0;mat.a[2][3]=0; 53 mat.a[3][1]=0;mat.a[3][2]=1;mat.a[3][3]=1; 54 node A=hh(mat,n-4); 55 // cout<<t<<endl; 56 cout<<(b[2]*A.a[1][3]%mod+b[3]*A.a[2][3]%mod+b[4]*A.a[3][3]%mod+mod)%mod<<endl; 57 58 } 59 return 0; 60 }
标签:std 快速 递推 str can using 思路 clu mem
原文地址:http://www.cnblogs.com/hhxj/p/6953432.html