UOJ Easy Round #11A. 切割冰片
UOJ Easy Round #11A. 切割冰片
观察到每条横线盖住的竖线不交且连续且单调。
设 表示考虑了前 条横线,前 条竖线。
枚举第 条横线覆盖了几条竖线。
若 ,则 。
若 ,则
发现相当于是对一个长度 的数组的前若干项做前缀和,然后询问和。
考虑优化 维。
法一
考虑快速维护一个结构,满足数列全体求前缀和,询问单点,全体加一个值,便可很好维护上述过程。
构造多项式:
做前缀和:
于是将系数右移即可,还可通过 实现全体加值。
将整个序列拆成 段,分别维护即可。
struct Poly {
int f[_], num;
void init () {
f[num = 0] = 0;
}
void add(int x) {
f[0] += x;
}
void upd() {
++num;
dF(i, num, 1) f[i] = f[i - 1];
f[0] = 0;
}
int qry(int x) {
int res = 0;
int nw = 1;
F(i, 0, num) {
res = (res + 1ll * f[i] * nw % mod) % mod;
nw = 1ll * nw * inv[i + 1] % mod * (x + i + 1) % mod;
}
return res;
}
} g[_];
法二
将整个序列拆成 段,维护每段的 阶前缀和。
阶前缀和公式:
路径计数,推推组合数即可。
dp[0][0] = f[0][0] = 1;
for (int i = 1; i <= tot; i++) f[0][i] = ADD(f[0][i - 1], dp[0][i]);
for (int i = 1; i <= n; i++) {
dp[i][0] = 1;
for (int j = 1; j <= tot; j++) {
if (L[i] < lsh[j]) {
for (int k = j; k <= tot; k++) dp[i][k] = dp[i - 1][k];
break ;
}
int res = 1, nn = lsh[j] - lsh[j - 1] - 1, mm = 0;
for (int k = i; k >= 1; k--) {
if (L[k] < lsh[j]) continue;
++nn, ++mm;
res = res * nn % mod * inv[mm] % mod;
dp[i][j] = ADD(dp[i][j], 1ll * f[k - 1][j - 1] * res % mod);
if (dp[i][j] < 0) dp[i][j] += mod;
}
}
f[i][0] = dp[i][0];
for (int j = 1; j <= tot; j++) f[i][j] = ADD(f[i][j - 1], dp[i][j]);
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121925