【HNOI2010】【BZOJ2004】Bus 公交線路
題目描述 Description
小 Z 所在的城市有 N 個公交車站,排列在一條長為 N-1 公里的直線上,從左到右依次編號為1到 N,相鄰公交車站間的距離均為 1公里。
作為公交車線路的規劃者,小 Z調查了市民的需求,決定按以下規則設計線路:
1. 設共有K輛公交車,則 1到K 號車站作為始發站,N-K+1到 N號車站作為終點站。
2. 每個車站必須被一輛且僅一輛公交車經停(始發站和終點站也算被經停)。
3. 公交車只能從編號較小的車站駛向編號較大的車站。
4. 一輛公交車經停的相鄰兩個車站間的距離不得超過P 公里。
注意“經停”是指經過並停車,因經過不一定會停車,故經停與經過是兩個不同的概念。
在最終確定線路之前,小 Z 想知道有多少種滿足要求的方案。由於答案可能很大,你只需求出答案對30031取模的結果。
輸入描述 Input Description
輸入檔案只有一行,其中包含用空格隔開的三個正整數N, K,
P,分別表示公交車站數,公交車數,一輛公交車經停的相鄰兩個車站間的最大距離。
輸出描述 Output Description
僅包含一個整數,表示滿足要求的方案數對30031取模的結果。
Sample Input
樣例一:10 3 3
樣例二:5 2 3
樣例三:10 2 4
Sample Output
1
3
81
資料範圍及提示 Data Size & Hint
輸入的資料保證40%的資料滿足N≤1000。100%的資料滿足1
由於BZOJ題面又一次掛了…從Codevs沾來了題面.
看到題目發現N這麼大,又是求路徑方案數,很自然的想到HH去散步,也就是把原圖變成矩陣然後做矩陣快速冪.
但是注意到題目裡還有個P,P還只有10,那說不定是狀壓DP.
然後呢…
我們假設現在有一列公交車,事先規定轉移時候先轉移最靠前的公交車.
用2^p的二進位制數表示狀態,這個數的二進位制位總共有k位為1,且為了滿足之前的規定最高位必須為1.
然後就可以p個p個轉移.
我們知道合法狀態最多有C(9,4)=126種.
然後狀壓DP+矩乘快速冪.搞定.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define P 30031
#define MAXN 20
#define SIZE 200
#define LL long long
#define lowbit(x) (x&(-x))
using namespace std;
int n,k,p,Size;
int Pow[MAXN]={1};
int cons[SIZE];
struct Matrix
{
LL a[SIZE][SIZE];
Matrix()
{
memset(a,0,sizeof(a));
}
inline friend Matrix operator *(Matrix A,Matrix B)
{
Matrix ret;
for (int i=1;i<=Size;i++)
for (int j=1;j<=Size;j++)
{
for (int k=1;k<=Size;k++)
ret.a[i][j]+=A.a[i][k]*B.a[k][j];
ret.a[i][j]%=P;
}
return ret;
}
inline friend Matrix operator ^(Matrix x,int N)
{
Matrix ret;
for (int i=1;i<=Size;i++) ret.a[i][i]=1;
for (int i=N;i;i>>=1,x=x*x)
if (i&1) ret=ret*x;
return ret;
}
}ans,_a,_b;
void init(int x,int num,int sum)
{
if (num==k)
{
cons[++Size]=sum;
return;
}
for (int i=x-1;i;i--) init(i,num+1,sum+Pow[i-1]);
}
void pre()
{
for (int i=1;i<=Size;i++)
for (int j=1;j<=Size;j++)
{
int x=((cons[i]<<1)^Pow[p])^cons[j];
if (x==lowbit(x)) _b.a[i][j]=1;
}
}
int main()
{
scanf("%d%d%d",&n,&k,&p);
for (int i=1;i<=p;i++) Pow[i]=Pow[i-1]<<1;
init(p,1,Pow[p-1]);pre();ans.a[1][1]=1;
_a=_b^(n-k);ans=ans*_a;
cout<<ans.a[1][1]<<endl;
}