BZOJ2004: [Hnoi2010]Bus 公交线路
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2004
状压dp+矩阵乘法。
f[i][s]表示从第i位至前面的i-k位,第i位必须取的状态。
然后p->p‘的转移是每一次只走一步的,强制其跑得最远的一位转移。
那么判断能否转移就是v[i]<<1^bin[p]与v[j]是否只有一位不同。
于是我们要强制令每个s中的第p位为1。。
然后跑n-k步矩阵乘法就可以了。
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define inf int(1e9) #define maxn 20 #define mm 30031 using namespace std; struct data{int a[205][205]; }ans,b; int bin[maxn],v[maxn],n,k,p,cnt; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } int lowbit(int x){ return (x&(-x)); } void dfs(int dep,int s,int now){ if (dep>k){ v[++cnt]=s; return ; } down(i,now-1,1){ dfs(dep+1,s+bin[i-1],i); } } void pre(){ rep(i,1,cnt) rep(j,1,cnt){ int x=(v[i]*2)^bin[p]; x=x^v[j]; if (x==lowbit(x)) b.a[i][j]=1; } } data operator *(data a,data b){ data c; clr(c.a,0); rep(i,1,cnt) rep(j,1,cnt) rep(k,1,cnt){ c.a[i][j]=(c.a[i][j]+(a.a[i][k]*b.a[k][j])%mm)%mm; } return c; } void pow(int x){ rep(i,1,cnt) ans.a[i][i]=1; while (x){ if (x&1) ans=ans*b; b=b*b; x/=2; } printf("%d\n",ans.a[1][1]); } int main(){ n=read(); k=read(); p=read(); bin[0]=1; rep(i,1,p) bin[i]=bin[i-1]*2; dfs(2,bin[p-1],p); pre(); pow(n-k); return 0; }