[HNOI2010]公交线路
不看题解不会做类型...
看到数据范围,显然要构造矩阵.
但是状态有那么多,于是要缩减状态.
设(dp[i][s])表示第i个车站和之后的p个车站,k辆车最后出没的位置.一辆车最多走p个车站,于是必定会在这p个车站出现至少一次,j就是一个长度为p的,含k个1的01串,最多有252种情况,转移只要在1之间转移就可以了,所以显然第一位没有车的状态可以缩掉.
每次转移只动一辆车,这样一步一步地走,不重不漏.转移矩阵构出来之后直接快速幂就可以了,最后要的状态是(dp[n-k][(1<<k)-1])
#include<bits/stdc++.h>
#define mod 30031
using namespace std;
int n,k,p,s,f[20],st[505];
int lowbit(int x){return x&-x;}
int calc(int x){int r=0;for(int i=x;i>=1;i-=lowbit(i),r++);return r;}
struct matrix
{
int a[150][150];
int *operator [] (int i){return a[i];}
matrix operator * (matrix x)
{
matrix y;memset(y.a,0,sizeof(y.a));
for(int i=1;i<=s;i++)
for(int j=1;j<=s;j++)
for(int k=1;k<=s;k++)
y[i][j]+=a[i][k]*x[k][j]%mod,y[i][j]%=mod;
return y;
}
}A,B;
void ksm(int k)
{
for(int i=1;i<=s;i++)A[i][i]=1;
while(k){if(k&1)A=A*B;k>>=1;B=B*B;}
}
int main()
{
cin>>n>>k>>p;//状态记录的是k辆车在i往后p个站点的最后出没点
for(int i=0;i<(1<<p);i++)//合法状态是第1个位置有车,区间里一定是k个最后出没点
if(calc(i)==k&&(i&1))st[++s]=i;
for(int i=1;i<=s;i++)
for(int j=1;j<=s;j++)
if(calc((st[i]>>1)&st[j])==k-1)B[i][j]=1;
ksm(n-k);
cout<<A[1][1]<<endl;
return 0;
}