题目:BZOJ2004.
题目大意:给定
n
,
m
,
k
n,m,k
n,m,k,要求将一个长度为
n
n
n的序列划分为
m
m
m份,其中每一份相邻两点的距离不超过
k
k
k.
1
≤
n
≤
1
0
9
,
1
≤
m
≤
8
,
1
≤
k
≤
10
1\leq n\leq 10^9,1\leq m\leq 8,1\leq k\leq 10
1≤n≤109,1≤m≤8,1≤k≤10,答案对
30031
30031
30031取模.
看到 m , k m,k m,k的数据范围都非常小,可以考虑状压.
设 f [ i ] [ S ] f[i][S] f[i][S]表示到目前 [ 1 , i − 1 ] [1,i-1] [1,i−1]都划分完毕,且 [ i , i + k − 1 ] [i,i+k-1] [i,i+k−1]的选取状态为 S S S的方案数.为了避免漏选的情况,每次转移的时候我们都钦定 i i i这个位置必须选.
之后转移的时候,从 i i i到 i + 1 i+1 i+1时,我们将后面的某一个空位划分给位置 i i i属于的那一份即可.
最后一个矩阵乘法快速幂优化这个DP即可.
时间复杂度 O ( ( k m ) 3 log n ) O(\binom{k}{m}^3\log n) O((mk)3logn).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define memset(a) memset(a,0,sizeof(a))
const int N=10,M=8,K=252,mod=30031;
int add(int a,int b,int p=mod){return a+b>=p?a+b-p:a+b;}
int sub(int a,int b,int p=mod){return a-b<0?a-b+p:a-b;}
int mul(int a,int b,int p=mod){return (LL)a*b%p;}
void sadd(int &a,int b,int p=mod){a=add(a,b,p);}
void ssub(int &a,int b,int p=mod){a=sub(a,b,p);}
void smul(int &a,int b,int p=mod){a=mul(a,b,p);}
struct matrix{
int n,m,mat[K][K];
matrix(int N=0,int M=0){n=N;m=M;memset(mat);}
int *operator [] (const int &p){return mat[p];}
}ans,go;
matrix Mat_mul(matrix a,matrix b){
matrix res(a.n,b.m);
for (int i=0;i<a.n;++i)
for (int j=0;j<a.m;++j)
for (int k=0;k<b.m;++k)
sadd(res[i][k],mul(a[i][j],b[j][k]));
return res;
}
matrix Mat_power(matrix a,int k){
matrix res(a.n,a.n);
for (int i=0;i<a.n;++i) res[i][i]=1;
for (;k;k>>=1,a=Mat_mul(a,a))
if (k&1) res=Mat_mul(res,a);
return res;
}
int n,m,sk;
int id[(1<<N)+9],ci;
void Get_id(){
for (int g=0;g<1<<sk;++g){
if (g&1^1) continue;
int cnt=0;
for (int i=0;i<sk;++i) cnt+=g>>i&1;
if (cnt^m) continue;
id[g]=++ci;
}
}
void Get_go(){
go.n=go.m=ci;
for (int g=0;g<1<<sk;++g){
if (!id[g]) continue;
int t=g>>1;
if (t&1^1) {go[id[t|1]-1][id[g]-1]=1;continue;}
for (int i=0;i<sk;++i)
if (t>>i&1^1&&id[t|1<<i]) go[id[t|1<<i]-1][id[g]-1]=1;
}
}
int Get_ans(){
int t=0;
for (int i=0;i<m;++i) t|=1<<i;
ans.n=1;ans.m=ci;
ans[0][t=id[t]-1]=1;
ans=Mat_mul(Mat_power(go,n-m),ans);
return ans[0][t];
}
Abigail into(){
scanf("%d%d%d",&n,&m,&sk);
}
Abigail work(){
Get_id();
Get_go();
}
Abigail outo(){
printf("%d\n",Get_ans());
}
int main(){
into();
work();
outo();
return 0;
}