SDOI2010 代码拍卖会

mac2022-06-30  125

SDOI2010 代码拍卖会

题意:

题目传送门

题解:

看完题目之后,第一反应应该就是数位\(Dp\)了,但是考虑到\(N\)非常的大,我们需要考虑另一种方法。注意到这个满足条件的数字的每一位都大于等于前一位,所以我们可以比较明显的发现,最后组成的数字一定可以表示成小于等于\(9\)\(111...111\)(若干个\(1\))这样形式的数字之和,随后可以发现这些数字在模\(p\)的意义下是有循环节的,所以我们可以设计一个\(Dp\),记\(cnt[i]\)表示模\(p\)\(i\)\(111...111\)这样的数字的个数,\(f[i][j][k]\)表示考虑了模\(p\)小于等于\(i\)的数,当前数字模\(p\)\(j\),已经选了\(k\)\(111...111\)这样的数字的方案数,转移方程就是\(f[i][j][k] * \binom{cnt[i] + t - 1}{t} \to f[i + 1][(j + t \times i) \% p][k + t]\)。最后注意由于每一个数都是\(1\),所以\(1111...111\)\(N\)\(1\))是必选的。

Code:

#include <bits/stdc++.h> using namespace std; const int N = 505; const int Md = 999911659; typedef long long ll; inline int Add(const int &x, const int &y) { return (x + y >= Md) ? (x + y - Md) : (x + y); } inline int Sub(const int &x, const int &y) { return (x - y < 0) ? (x - y + Md) : (x - y); } inline int Mul(const int &x, const int &y) { return (ll)x * y % Md; } int Powe(int x, int y) { int ans = 1; for(;y; y >>= 1, x = Mul(x, x)) if(y & 1) ans = Mul(ans, x); return ans; } int f[N][N][10], cho[N][10], inv[10]; ll n; ll cnt[N], st[N], num[N]; int p, sum, St, Ed; int main() { scanf("%lld%d", &n, &p); for(int i = 1; i <= n; i++) { sum = sum * 10 + 1; sum %= p; if(st[sum]) { St = st[sum]; Ed = i; break; } cnt[sum]++; st[sum] = i; num[i] = sum; } int len = 0; if(St) { len = Ed - St; ll c = n - Ed + 1; ll d = c / len, m = c % len; for(int i = St; i < Ed; i++) cnt[num[i]] += d; for(int i = St; i < Ed && m; i++, m--) cnt[num[i]] ++; } cnt[0]++; inv[1] = 1; for(int i = 2; i <= 9; i++) inv[i] = Mul(Md - Md / i, inv[Md % i]); for(int i = 0; i < p; i++) { cnt[i] %= Md; cho[i][0] = 1; for(int j = 1; j <= 8; j++) { cho[i][j] = Mul(Mul(cnt[i] % Md, cho[i][j - 1]), inv[j]); cnt[i] = Add(cnt[i], 1); } } if(!len) { f[0][num[n]][0] = 1; for(int i = 0; i < p; i++) { for(int j = 0; j < p; j++) { for(int k = 0; k <= 8; k++) { for(int t = 0; t <= k; t++) { if(!f[i][(j - t * i % p + p) % p][k - t]) continue; f[i + 1][j][k] = Add(f[i + 1][j][k], Mul(f[i][(j - t * i % p + p) % p][k - t], cho[i][t])); } } } } printf("%d\n", f[p][0][8]); return 0; } int las = (n - Ed + 1) % len; if(!las) las += len; f[0][num[St + las - 1]][0] = 1; for(int i = 0; i < p; i++) { for(int j = 0; j < p; j++) { for(int k = 0; k <= 8; k++) { for(int t = 0; t <= k; t++) { if(!f[i][(j - t * i % p + p) % p][k - t]) continue; f[i + 1][j][k] = Add(f[i + 1][j][k], Mul(f[i][(j - t * i % p + p) % p][k - t], cho[i][t])); } } } } printf("%d\n", f[p][0][8]); return 0; }

转载于:https://www.cnblogs.com/Apocrypha/p/10639135.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)