1. 程式人生 > >hdu 6030

hdu 6030

tin type == ons 區間 得到 i++ include 字符

題意: 給出紅藍兩種,然後排成一個字符串,要求在每一個長度為素數的區間裏面是的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 }

hdu 6030