[Hnoi2010]Bus 公交線路
阿新 • • 發佈:2018-09-22
des utc span 問題 設計 規劃 小z 結果 include
N<=10^9,1<P<=10,K<N,1<K<=P
(\(sta\)上第\(k\)位為1說明第\(k\)個車站上停了車),很容易推出轉移方程式為\(f[i][sta]=\sum\limits_{j=k}^{i-1}f[j][sta']\),\(sta'\)到\(sta\)的轉移是合法的。
Description
小Z所在的城市有N個公交車站,排列在一條長(N-1)km的直線上,從左到右依次編號為1到N,相鄰公交車站間的距離均為1km。
作為公交車線路的規劃者,小Z調查了市民的需求,決定按下述規則設計線路:
- 設共K輛公交車,則1到K號站作為始發站,N-K+1到N號臺作為終點站。
- 每個車站必須被一輛且僅一輛公交車經過(始發站和終點站也算被經過)。
- 公交車只能從編號較小的站臺駛往編號較大的站臺。
- 一輛公交車經過的相鄰兩個站臺間距離不得超過Pkm。
在最終設計線路之前,小Z想知道有多少種滿足要求的方案。
由於答案可能很大,你只需求出答案對30031取模的結果。
Input
僅一行包含三個正整數N K P,分別表示公交車站數,公交車數,相鄰站臺的距離限制。
Output
僅包含一個整數,表示滿足要求的方案數對30031取模的結果。
Sample Input 1
10 3 3
Sample Output 1
1
Sample Input 2
5 2 3
Sample Output 2
3
Sample Input 3
10 2 4
Sample Output 3
81
看到\(p\leqslant 10\),這題肯定要狀壓;看到\(n\leqslant 10^9\),這題肯定要矩陣乘法
用\(f[i][sta]\)表示最快的公交車到了第\(i\)個車站,當前停靠公交車的站臺的狀態為\(sta\)
然後註意到題目有限制:一個公交車經過的兩個相鄰的站臺之間的距離不超過\(p\),這樣可以把\(sta\)的枚舉範圍從\(\[1,2^n-1\]\)縮小到\(\[1,2^p-1\]\),那麽空間上就沒啥問題了。
然後我們發現對於每個\(f[i][sta]\)來說,拿來轉移到它的\(sta'\)都是一樣的,那麽我們可以用矩乘優化來加速這個DP
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1.5e2,MOD=30031;
int n,k,p,tot;
struct Matrix{
int v[N+10][N+10];
Matrix(){memset(v,0,sizeof(v));}
void init(){for (int i=1;i<=tot;i++) v[i][i]=1;}
}trans,Ans;
Matrix operator *(const Matrix &x,const Matrix &y){
Matrix z;
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
for (int k=1;k<=tot;k++)
z.v[i][k]=(z.v[i][k]+x.v[i][j]*y.v[j][k])%MOD;
return z;
}
Matrix mlt(Matrix a,int b){
Matrix res; res.init();
for (;b;b>>=1,a=a*a) if (b&1) res=res*a;
return res;
}
int calc(int x){
int res=0;
while (x) res++,x-=lowbit(x);
return res;
}
bool check(int Now,int To){
Now<<=1;
int tmp=0;
for (int i=0;i<p;i++) if ((Now&(1<<i))^(To&(1<<i))) tmp++;
return tmp<2;
}
int stack[(1<<10)+10];
int main(){
n=read(),k=read(),p=read();
int Endl=0;
for (int sta=(1<<(p-1));sta<1<<p;sta++){
if (calc(sta)==k){
stack[++tot]=sta;
if (sta==(1<<p)-(1<<(p-k))) Endl=tot;
}
}
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
if (check(stack[i],stack[j]))
trans.v[i][j]=1;
Ans.v[1][Endl]=1;
Ans=Ans*mlt(trans,n-k);
printf("%d\n",Ans.v[1][Endl]);
return 0;
}
[Hnoi2010]Bus 公交線路