简要题意:
统计有多少个不同的 n n n 排列满足 ∣ p i − i ∣ ≤ k |p_i-i|\leq k ∣pi−i∣≤k
k ≤ 4 k\leq 4 k≤4
题解:
容易发现当前位置选择哪一个只会影响到后面 k k k 个位置。 k k k 本身非常小,状压即可。
容易发现转移和当前是第几位无关,只和状态有关,而且是线性,写成矩阵然后快速幂即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
int nn;
struct mat{
int a[256][256];mat(){memset(a,0,sizeof a);}
int* operator[](int o){return a[o];}
cs int* operator[](int o)cs{return a[o];}
};
mat operator*(cs mat &A,cs mat &B){
static mat C;memset(C.a,0,sizeof C.a);
for(int re i=0;i<nn;++i)
for(int re j=0;j<nn;++j)
for(int re k=0;k<nn;++k)
Inc(C[i][k],mul(A[i][j],B[j][k]));
return C;
}
int n,k;
mat ans,tr;
void Main(){
while(scanf("%d%d",&n,&k)!=EOF){
nn=1<<(k<<1);
memset(ans.a,0,sizeof ans.a);
memset(tr.a,0,sizeof tr.a);
ans[0][(1<<k)-1]=1;
for(int re s=0;s<nn;++s){
if(~s&1){
tr[s][s>>1]=1;
continue;
}
for(int re i=1;i<=k+k;++i)
if(~s&(1<<i))tr[s][(s|(1<<i))>>1]=1;
}while(n){
if(n&1)ans=ans*tr;
if(n>>=1)tr=tr*tr;
}cout<<ans[0][(1<<k)-1]<<"\n";
}
}
inline void file(){
#ifdef zxyoi
freopen("permutation.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
#endif
#endif
}signed main(){file();Main();return 0;}