HDU6030----矩阵快速幂

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

思路二:考虑放第i个时的情况,如果放r则有S[n-1]种情况,如果放b则要求i-1和i-2的位置上必须都是r。则Si = S[i-1] + S[i-3];

 

由于数据有1018

所以考虑矩阵快速幂

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define LL long long int
#define R(i,n) for(int i = 0; i < n; i++)
using namespace std;
const LL mod = 1e9+7;
struct node{
    LL c[3][3];
} t,temp;
LL n;
node mul(node a,node b){//矩阵乘法
   node c;
    int i,j,k;
    for(i=0;i<3;i++){
        for(j=0;j<3;j++){
            c.c[i][j]=0;
            for(k=0;k<3;k++)
                c.c[i][j]+=(a.c[i][k]*b.c[k][j])%mod;
        c.c[i][j]=c.c[i][j]%mod;
        }
    }
    return c;
}
node kuaisumi(LL n){
   node res;
   memset(res.c,0,sizeof(res.c));
   for(int i = 0; i < 3; i++)
        res.c[i][i] = 1;
   t.c[0][0] = 1;t.c[0][1] = 1;t.c[0][2] = 0;
   t.c[1][0] = 0;t.c[1][1] = 0;t.c[1][2] = 1;
   t.c[2][0] = 1;t.c[2][1] = 0;t.c[2][2] = 0;
    if(n<0)
        return res;
    while(n){
        if(n&1)
            res=mul(res,t);
        t=mul(t,t);
        n=n>>1;
    }
    return res;
}
int main(){
    //freopen("C:\\Users\\admin\\Desktop\\1.in","r",stdin);
    //freopen("C:\\Users\\admin\\Desktop\\1.out","w",stdout);
    std::ios::sync_with_stdio(false);
    int T_T;
    cin>>T_T;
    while(T_T--){
        cin>>n;
        LL a[] = {0,2,3,4,6};
        if(n <= 4){
            cout<<a[n]<<endl;
            continue;
        }
        node ret = kuaisumi(n-4);
        cout<<(a[4]*ret.c[0][0]+a[3]*ret.c[1][0]+a[2]*ret.c[2][0])%mod<<endl;
    }
}

  

posted @ 2017-08-02 10:22  OMG_By  阅读(152)  评论(0编辑  收藏  举报