首页 > 代码库 > hdu 6030

hdu 6030

题意: 给出红蓝两种,然后排成一个字符串,要求在每一个长度为素数的区间里面是的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