[HNOI 2010]Bus 公交線路
阿新 • • 發佈:2018-03-12
pro lowbit gpo online 容易 矩陣 公交 沒有 c++
個狀態即 \(C_9^5=126\) 這樣一來我們容易想到用矩陣乘法來優化遞推。
Description
題庫鏈接
有 \(N\) 個車站, \(K\) 條公交線路。第 \(1\) 到 \(K\) 站是這 \(K\) 線路的起點站。第 \(N-K+1\) 到 \(N\) 是終點站。車只會從編號小的車站駛向編號大的車站。
要求每個車站恰好只屬於一個線路,而且同一個線路相臨兩站距離不得大於 \(P\) 。求有多少種安排方法。輸出答案對 \(30031\) 取余數。
\(1\leq N\leq 10^9,1<K\leq P\leq 10,K<N\)
Solution
不妨拋開前 \(K\) 個車站不看。
我們發現,只要每連續的 \(P\) 個站中,都出現了所有 \(K\) 種公交車,方案就是合法的。
證明:
如果方案不合法,必有一線路有相鄰站距離大於 \(P\) ,即這連續 \(P\) 個站中缺少一種公交車。根據逆否命題等價,得證。
由於沒有線路車站數的限制, \(P\) 又不大,容易想到狀態壓縮動態規劃:
\(F_{i,S}\) 表示:前 \(i\) 位已經確定完畢,不同公交車最後經停站距 \(i+1\) 的位置的狀態為 \(S\) ,此時的方案總數。
由於公交車是無差別的, \(S\) 實際上是 \(K\) 個不同整數的集合。每個元素都是 \(1\) 到 \(P\) 的數。
更進一步,集合 \(S\) 中一定有一個元素 \(1\) ,其余的都是 \(2\) 到 \(P\) 。
所以最大只有 \(C_{P-1}^{K-1}\)
Code
//It is made by Awson on 2018.3.12
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int yzh = 30031, SIZE = (1<<10);
void read(int &x) {
char ch; bool flag = 0;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
x *= 1-2*flag;
}
void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
int n, k, p, bin[20], cnt, sta[130], fin, mp[1050];
struct mat {
int a[130][130];
mat() {memset(a, 0, sizeof(a)); }
mat(int _a[130][130]) {for (int i = 1; i <= 126; i++) for (int j = 1; j <= 126; j++) a[i][j] = _a[i][j]; }
mat operator * (const mat &b) const {
mat ans;
for (int i = 1; i <= cnt; i++)
for (int j = 1; j <= cnt; j++)
for (int k = 1; k <= cnt ; k++)
ans.a[i][j] = (ans.a[i][j]+1ll*a[i][k]*b.a[k][j]%yzh)%yzh;
return ans;
}
}S, T;
mat quick_pow(mat a, int b) {
mat ans = a; b--;
while (b) {
if (b&1) ans = ans*a;
a = a*a, b >>= 1;
}
return ans;
}
int bitcount(int x) {int ans = 0; while (x) x -= lowbit(x), ++ans; return ans; }
void work() {
read(n), read(k), read(p); bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = (bin[i-1]<<1);
for (int i = 0; i < bin[p-1]; i++) if (bitcount(i) == k-1) sta[++cnt] = (i<<1|1), mp[i<<1|1] = cnt;
for (int i = 1; i <= cnt; i++) {
if (sta[i] == bin[k]-1) S.a[i][i] = 1, fin = i;
int t = sta[i];
if (t&bin[p-1]) T.a[i][mp[(t-bin[p-1])<<1|1]] = 1;
else for (int x = t; x; x -= lowbit(x)) T.a[i][mp[(t-lowbit(x))<<1|1]] = 1;
}
S = S*quick_pow(T, n-k); writeln(S.a[fin][fin]);
}
int main() {
work(); return 0;
}
[HNOI 2010]Bus 公交線路