Atcoder Beginner Contest 154 E-F 题解
E - Almost Everywhere Zero
解法:简单的数位dp
- f 为是否在判前导0,g 为是否在卡上界
- num=0 时刚好有 k 个不为0 的数位
ll dp[110][4][2][2];
// f 为是否在判前导0,g 为是否在卡上界
ll dfs(int cur, int num, bool f, bool g) {
//cout << "xxx " << cur << ' ' << num << ' ' << f << ' ' << g << '\n';
if (num < 0) return 0;
if (dp[cur][num][f][g] != -1) return dp[cur][num][f][g];
if (cur == str.size()) {
// num=0 时刚好有 k 个不为0 的数位
if (num == 0) return 1;
else return 0;
}
ll res = 0;
int x = !g ? 9 : str[cur] - '0';
ll ans = 0;
//cout << x << '\n';
for (int i = 0;i <= x;i++) {
if (i == 0) ans += dfs(cur + 1, num, f & (i == 0), g & (i == x));
else ans += dfs(cur + 1, num - 1, f & (i == 0), g & (i == x));
}
return dp[cur][num][f][g] = ans;
}
void solve() {
cin >> str >> k;
memset(dp, -1, sizeof(dp));
cout << dfs(0, k, 1, 1) << '\n';
}
F -Many Many Paths (NTT做法)
数据范围:1e6 + 1e6
解法:
-
可以用 ntt 强凹, 但因为我不知道 1e9+7 的ntt, 所以用的任意模数 ntt 的板子。
-
C(x+y,x) = (x+y)! / x! / y! , 则可转化为 指数型生成函数,相乘,最后将得到的每个位乘以 i! 加起来就完了。
-
代码块
// 记得此处是任意模数 ntt 的板子 // 可以在洛谷找一个 n = m = 1e6 + 10; int lx = read(), ly = read(), rx = read(), ry = read(); for (int i = lx;i <= rx;i++) A[i] = Int(invfac[i]); for (int i = ly;i <= ry;i++) B[i] = Int(invfac[i]); Poly::init(n + m); Poly::NTT(A), Poly::NTT(B); for (int i = 0; i < Poly::lim; ++i) A[i] = A[i] * B[i]; Poly::NTT(A, 0); ll res = 0; for (int i = 0; i < n + m - 1; ++i) res = (res + fac[i] * A[i].get() % mod) % mod; printf("%lld\n", res);