由题意易得递推式:
f[i]=f[i-1]+f[i-2]*4+f[i-3]*2
其中长度为1的消除方法只有一种,长度为2的消除方法是4种(不包括与长度为1重复的一种),长度为三的消除方法一共有2种。
注意,f[0]=1。
但由于数据量巨大!!!(giant)我们想到了矩阵快速幂的优化。
下面一起来推一推:
用类似fibonacci矩阵乘法的方法,这里用到了一个3*3的矩阵。
首先答案矩阵是:
{f[i]
f[i+1]
f[i+2]}
要将它变成矩阵:
{f[i+1]
f[i+2]
f[i+3]}
只需用计算矩阵:
{0 1 0
0 0 1
2 4 1} 乘上 答案矩阵 即可。
所以只需要将计算矩阵自乘n-3次,再将得到的矩阵第三行相加即使答案。代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int mod=1000000007;
LL n;
struct node{
LL g[4][4];
void init(){
g[1][1]=g[1][3]=g[2][1]=g[2][2]=0;
g[1][2]=g[2][3]=1;g[3][1]=2;
g[3][2]=4;g[3][3]=1;
}
};
node operator *(node A,node B){
node ret;
memset(ret.g,0,sizeof(ret.g));
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
ret.g[i][j]=(ret.g[i][j]+(A.g[i][k]*B.g[k][j])%mod)%mod;
return ret;
}
node pow(node a,LL b){
bool flag=false;
node ans;
while(b){
if(b&1LL){
if(!flag) ans=a;
else ans=ans*a;
flag=true;
}
a=a*a;
b>>=1;
}
return ans;
}
int main(){
scanf("%lld",&n);
if(n==0) printf("1");
else if(n==1) printf("1");
else if(n==2) printf("5");
else if(n==3) printf("11");
else{
node a;
a.init();
a=pow(a,n-3);
printf("%lld",(a.g[3][1]*1+a.g[3][2]*5+a.g[3][3]*11)%mod);
}
return 0;
}
^_^