@ZCDHJ
2019-08-06T07:30:55.000000Z
字数 1287
阅读 530
未分类
通过样例可以得知题意中的第 个始发站发第 列车。那么题意可以解读为将 个格子填上 数,最后 个格子需要有所有的数,每个长度为 的子区间都必须包含所有的数。发现 很小,所以设 为前 个格子已经填完,后 个格子的是否填涂的二进制状态。为了满足题目的限制,强制 的二进制第一位是 ,总共有 个一。那么 能从 转移过来的条件就是 去掉第一位后面补上一个零后只与 有一个二进制位不一样( 是零 是一)。然后矩阵快速幂就完事了。
#include <iostream>#include <cstdio>#include <cstring>const int MOD = 30031;int n, K, P, cnt;int S[256];struct Matrix {int a[127][127];Matrix() {memset(a, 0, sizeof(a));}friend Matrix operator* (const Matrix &lhs, const Matrix &rhs) {Matrix res;for (int i = 1; i <= 126; ++i) {for (int j = 1; j <= 126; ++j) {for (int k = 1; k <= 126; ++k) {res.a[i][j] = (res.a[i][j] + (lhs.a[i][k] * rhs.a[k][j]) % MOD) % MOD;}}}return res;}} dp, d, ans;inline int read() {register int x = 0;register char ch = getchar();while (!isdigit(ch)) ch = getchar();while (isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}return x;}Matrix quickPow(Matrix x, int y) {Matrix res = x, base = x;--y;while (y > 0) {if (y & 1) res = res * base;base = base * base;y >>= 1;}return res;}int main() {n = read();K = read();P = read();int ansPos = 0;for (int i = 1 << (P - 1); i < 1 << P; ++i) {int tmp = i, sum = 0;while (tmp > 0) sum += (tmp & 1), tmp >>= 1;if (sum == K) S[++cnt] = i;if (i == ((1 << K) - 1) << (P - K)) dp.a[1][cnt] = 1, ansPos = cnt;}for (int i = 1; i <= cnt; ++i) {for (int j = 1; j <= cnt; ++j) {int tmp = S[i] ^ (1 << (P - 1)), sum = 0;tmp = (tmp << 1) ^ S[j];while (tmp > 0) sum += (tmp & 1), tmp >>= 1;if (sum == 1) {d.a[i][j] = 1;}}}dp = dp * quickPow(d, n - K);printf("%d\n", dp.a[1][ansPos]);return 0;}