题目链接:http://codeforces.com/contest/1131/problem/D
题意:给你n个位置,每个位置上有一个宝珠,原宝珠(未分解的)都用1表示。现在你可以将连续的m个宝珠变成0(不得重叠),问最后构成n个位置宝珠的01串有几种方法。 1<=n<=1e18,1<=m<=100.
很明显,是要从不大的m下手作文章。也比较容易想得到递推式。如果f(n)表示n个宝珠的01串种数,则f(n+1)=f(n)+f(n-m).即n+1个01串就是在n个串上加个1或者n-m个的串上加m个0得来。可是直接递推很明显会T,所以用了一个快速幂优化。
我的小总结,如果是先到了某一个数之前的已知的话,则两边相加为n+1即可。
上代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
const ll mod=1e9+7;
struct matrix{
ll aim[102][102];
void clea(){
memset(aim,0,sizeof(aim));
for(int i=1;i<=100;i++)aim[i][i]=1;
}
};
ll n,m;
matrix mul(matrix a,matrix b){
matrix ans;
memset(ans.aim,0,sizeof(ans.aim));
for(ll i=1;i<=m;i++){
for(ll j=1;j<=m;j++){
for(ll k=1;k<=m;k++){
ans.aim[i][j]=(ans.aim[i][j]+a.aim[i][k]*b.aim[k][j])%mod;
}
}
}
return ans;
}
matrix quick(matrix a,ll k){
matrix ans;
ans.clea();
while(k){
if(k&1){
ans=mul(ans,a);
}
a=mul(a,a);
k/=2;
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
if(n<m){
printf("1\n");
return 0;
}
matrix st,a;
for(int i=1;i<=m;i++)
st.aim[i][1]=1;
a.aim[1][1]=a.aim[1][m]=1;
for(int i=2;i<=m;i++)
a.aim[i][i-1]=1;
matrix ans=quick(a,n-m+1);
ans=mul(ans,st);
ll now=0;
printf("%lld\n",ans.aim[1][1]);
return 0;
}