I - 快来快来数一数 FZU - 2198

n个六边形排成一行,相邻两个六边形共用一条边,如下图所示:

记这个图形的生成树个数为t(n)(由于每条边都是不同的,不存在同构的问题)。那么t(1)=6,t(2)=35……
给出n,求 mod 1000000007
Input
第一行给出数据组数T。
之后每一行给出一个正整数n。
T大约为50000,n<=10^18。
Output
每组数据输出一行答案。
Sample Input
2
2
12345678987654321
Sample Output
41

733521876

诶,矩阵快速幂还是不会啊

点击打开链接

这题用矩阵快速幂做,先用dp[i][f]表示处理到第i个矩形,第i个矩形右边那条边会不会不去掉的方案数,那么dp[i][1]=d[i-1][0]+dp[i-1][1],dp[i][0]=4*dp[i-1][1]+5*dp[i-1][0].
我们可以构造矩阵【dp[i][1],dp[i][0],sum[i]  】*A=【dp[i+1][1],dp[i+1][0],sum[i+1]  】.
                   1 4 5
容易求出A=1 5 6
                   0 0 1
然后用矩阵快速幂就行了,这里要注意,这题卡常数,所以要先初始化64个矩阵的乘方,然后再算,而且注意取模不能取太多,不然会超时。

#include<iostream>  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<math.h>  
#include<vector>  
#include<map>  
#include<set>  
#include<queue>  
#include<stack>  
#include<string>  
#include<algorithm>  
using namespace std;  
typedef unsigned long long ll;  
#define inf 0x7fffffff  
#define pi acos(-1.0)  
#define MOD 1000000007  
struct matrix{  
    int n,m,i;  
    ll data[3][3];  
}a,b,c,d[99],t;  
  
matrix multi(matrix &a,matrix &b){  
    matrix ans;  
    memset(ans.data,0,sizeof(ans.data));  
    ans.data[0][0]=(ans.data[0][0]+a.data[0][0]*b.data[0][0]);  
    ans.data[0][1]=(ans.data[0][1]+a.data[0][0]*b.data[0][1]);  
    ans.data[0][2]=(ans.data[0][2]+a.data[0][0]*b.data[0][2]);  
    ans.data[0][0]=(ans.data[0][0]+a.data[0][1]*b.data[1][0]);  
    ans.data[0][1]=(ans.data[0][1]+a.data[0][1]*b.data[1][1]);  
    ans.data[0][2]=(ans.data[0][2]+a.data[0][1]*b.data[1][2]);  
    ans.data[0][0]=(ans.data[0][0]+a.data[0][2]*b.data[2][0])%MOD;  
    ans.data[0][1]=(ans.data[0][1]+a.data[0][2]*b.data[2][1])%MOD;  
    ans.data[0][2]=(ans.data[0][2]+a.data[0][2]*b.data[2][2])%MOD;  
  
  
    ans.data[1][0]=(ans.data[1][0]+a.data[1][0]*b.data[0][0]);  
    ans.data[1][1]=(ans.data[1][1]+a.data[1][0]*b.data[0][1]);  
    ans.data[1][2]=(ans.data[1][2]+a.data[1][0]*b.data[0][2]);  
    ans.data[1][0]=(ans.data[1][0]+a.data[1][1]*b.data[1][0]);  
    ans.data[1][1]=(ans.data[1][1]+a.data[1][1]*b.data[1][1]);  
    ans.data[1][2]=(ans.data[1][2]+a.data[1][1]*b.data[1][2]);  
    ans.data[1][0]=(ans.data[1][0]+a.data[1][2]*b.data[2][0])%MOD;  
    ans.data[1][1]=(ans.data[1][1]+a.data[1][2]*b.data[2][1])%MOD;  
    ans.data[1][2]=(ans.data[1][2]+a.data[1][2]*b.data[2][2])%MOD;  
  
  
    ans.data[2][0]=(ans.data[2][0]+a.data[2][0]*b.data[0][0]);  
    ans.data[2][1]=(ans.data[2][1]+a.data[2][0]*b.data[0][1]);  
    ans.data[2][2]=(ans.data[2][2]+a.data[2][0]*b.data[0][2]);  
    ans.data[2][0]=(ans.data[2][0]+a.data[2][1]*b.data[1][0]);  
    ans.data[2][1]=(ans.data[2][1]+a.data[2][1]*b.data[1][1]);  
    ans.data[2][2]=(ans.data[2][2]+a.data[2][1]*b.data[1][2]);  
    ans.data[2][0]=(ans.data[2][0]+a.data[2][2]*b.data[2][0])%MOD;  
    ans.data[2][1]=(ans.data[2][1]+a.data[2][2]*b.data[2][1])%MOD;  
    ans.data[2][2]=(ans.data[2][2]+a.data[2][2]*b.data[2][2])%MOD;  
    return ans;  
  
    /* 
    for(int i=0;i<3;i++){ 
        for(int k=0;k<3;k++){ 
                if(a.data[i][k]>0) 
                for(int j=0;j<3;j++){ 
                    ans.data[i][j]=(ans.data[i][j]+a.data[i][k]*b.data[k][j])%MOD; 
                } 
        } 
    } 
    return ans; 
    */  
}  
  
matrix fast_mod(ll n){  
    matrix ans;  
    ans.n=3;  
    ans.m=3;  
    memset(ans.data,0,sizeof(ans.data));  
    ans.data[0][0]=ans.data[1][1]=ans.data[2][2]=1;  
    int num=1;  
    while(n>0){  
        if(n&1){  
            ans=multi(ans,d[num]);  
        }  
        num++;  
        n>>=1;  
    }  
    printf("%I64d\n",(ans.data[0][2]+5*ans.data[1][2]+6*ans.data[2][2]  )%MOD);  
}  
  
void init()  
{  
    int i,j;  
    d[1].n=d[1].m=3;  
    d[1].data[0][0]=1;  
    d[1].data[0][1]=4;  
    d[1].data[0][2]=5;  
    d[1].data[1][0]=1;  
    d[1].data[1][1]=5;  
    d[1].data[1][2]=6;  
    d[1].data[2][0]=0;  
    d[1].data[2][1]=0;  
    d[1].data[2][2]=1;  
    for(i=2;i<64;i++){  
        d[i]=multi(d[i-1],d[i-1]);  
    }  
}  
  
int main()  
{  
    ll n,m,i,j;  
    int T;  
    init();  
    scanf("%d",&T);  
    while(T--)  
    {  
        scanf("%I64d",&n);  
        if(n==0){  
            printf("0\n");  
            continue;  
        }  
        fast_mod(n-1);  
    }  
    return 0;  
}  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值