题目
题意:
在
n
(
<
=
1
0
9
)
n(<=10^9)
n(<=109)个星球中,一个人能从x号星球到y号星球当且仅当y没有被访问过并且
1
<
=
y
<
=
x
+
m
(
m
<
=
4
)
1<=y<=x+m(m<=4)
1<=y<=x+m(m<=4)。
求走
k
(
<
=
12
)
k(<=12)
k(<=12)步的方案数。
发现按走的顺序
d
p
dp
dp不好记录状态。
那就强行按从大编号往小编号
d
p
dp
dp,
在考虑把当前编号
x
x
x(为最小编号)插入行走序列的方案数,
也就是记一下
x
+
1
,
x
+
2
,
.
.
,
x
+
m
x+1,x+2,..,x+m
x+1,x+2,..,x+m是否被走过(那么就可以把
x
x
x插到
x
+
k
x+k
x+k前面),
这个就可以状压了然后矩阵加速了。
AC Code:
#include<bits/stdc++.h>
#define maxn 250
#define mod 1000000007
using namespace std;
int n,k,m;
int S,M;
int bit[maxn];
struct mat{
int a[maxn][maxn];
mat (int d=0){memset(a,0,sizeof a);for(int i=0;i<maxn;i++) a[i][i]=d;}
mat operator *(const mat &B)const{
mat ret = mat(0);
for(int i=0;i<S;i++)
for(int j=0;j<S;j++) if(a[i][j])
for(int k=0;k<S;k++) if(B.a[j][k])
ret.a[i][k] = (ret.a[i][k]+ a[i][j] * 1ll * B.a[j][k])%mod;
return ret;
}
}A;
mat Pow(mat base,int k){
mat ret = mat(1);
for(;k;k>>=1,base=base*base)
if(k&1)
ret=ret*base;
return ret;
}
int main(){
scanf("%d%d%d",&n,&k,&m);
M = 1<<m;
S = (k+1) * M;
for(int sta=1;sta<M;sta++)
bit[sta] = bit[sta-(sta&-sta)] + 1;
for(int sta=0;sta<M;sta++)
for(int i=0;i<=k;i++){
A.a[i*M+sta][i*M+((sta<<1)&(M-1))]++;
if(i<k)A.a[i*M+sta][(i+1)*M+((sta<<1)&(M-1))+1]+=bit[sta]+1;
}
A = Pow(A,n);
int ans = 0;
for(int sta=0;sta<M;sta++){
ans = (ans + A.a[0][k*M+sta])%mod;
}
printf("%d\n",(ans+mod)%mod);
}