Problem 2198 快来快来数一数
Accept: 67 Submit: 194
Time Limit: 1000 mSec Memory Limit : 65536 KB
Problem Description
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
Source
FOJ有奖月赛-2015年10月
Submit Back Status Discuss
用dp[i][0]表示,有i个六边形,没有最右边的个数。
dp[i][1]表示,有i个六边形,有最右边的个数。
dp[i][2]表示,前i个,总的方案数。答案就是dp[n][2];
i个六边形总个数就是dp[i][0] + dp[i][1];
dp[i+1][0] = dp[i][0] + dp[i][1];上图中1 2情况,新加的六边形,只有一种方法。
dp[i+1][1] = dp[i][0] * 4 + dp[i][1] * 5;上图中3 4 5情况,新加的图形有4种方式去边,还有一种方法,就是把最右边的边去掉,再加入5条边有1种方法.
这样就可以用矩阵快速幂来求了。
dp[i][0] dp[i][1] dp[i][2]
0 0 0
0 0 0
*
1 4 5
1 5 6
0 0 1
=
dp[i+1][0] dp[i+1][1] dp[i+1][2]
0 0 0
0 0 0
总的复杂度为o( T * log(n) * 27);
这题竟然还卡常数,没办法,只好预处理一下矩阵。
#define N 3
#define M 100005
#define maxn 205
#define MOD 1000000007
struct node{
ll c[N][N];
};
node one[100];
node mulnode(node a,node b){
node c;
FI(N){
FJ(N){
c.c[i][j] = 0;
For(k,0,N){
c.c[i][j] = (c.c[i][j] + a.c[i][k] * b.c[k][j]) % mod;
}
}
}
return c;
}
void Init(){
memset(one[0].c,0,sizeof(one[0].c));
one[0].c[0][0] = 1;
one[0].c[0][1] = 4;
one[0].c[0][2] = 5;
one[0].c[1][0] = 1;
one[0].c[1][1] = 5;
one[0].c[1][2] = 6;
one[0].c[2][0] = 0;
one[0].c[2][1] = 0;
one[0].c[2][2] = 1;
For(i,1,100){
one[i] = mulnode(one[i-1],one[i-1]);
}
}
ll twoMulti(ll x){
node ans;
memset(ans.c,0,sizeof(ans.c));
ans.c[0][0] = 1;
ans.c[0][1] = 5;
ans.c[0][2] = 6;
int i = 0;
while(x){
if(x&1){
ans = mulnode(ans,one[i]);
}
x/=2;
i++;
}
return ans.c[0][2];
}
int T;
ll nn;
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
Init();
while(S(T)!=EOF)
{
while(T--)
{
scanf("%lld",&nn);
printf("%lld\n",twoMulti(nn - 1));
}
}
//fclose(stdin);
//fclose(stdout);
return 0;
}