CF1842G
第一次听没听懂,补个笔记。弄懂这种奇妙拆贡献后感觉非常厉害。
答案的形式为:\(\prod (a_i + k \cdot v)\),这些 \(v\) 是前面的操作带来的影响。
我们考虑一个个加入这个 \((a_i + k \cdot v)\),并且维护很多个等价类,使得这个值可以根据分开等价类的那个标志被确认。
\(k\),不过是前面的数字被操作了多少次。因此划分等价类的标志是:前面的数字一共被操作了多少次。即:\(f_{i, j}\) 表示:考虑前 \(i\) 个数,这些数字加起来被操作了 \(j\) 次,\(\prod (a_i + k \cdot v)\) 值之和。
转移:
这个是 \(O(n^3)\) 的,过不去。
发现复杂度瓶颈是枚举 \(k\),也就是,操作多少次当前点。我们拆开这 \(k\) 次操作,也不计算这 \(k\) 次操作带来的贡献。或者说,这 \(k\) 次操作直到后面才会影响不同的值,因此,到后面再做区分。
因为不区分多次操作,这启示我们分开所有 \(v\) 的贡献,即:用分配律拆开全部式子,每一项是 \(v\) 或一个 \(a_i\),计算和。
转移时,枚举产生贡献的是 \(a_i\),已经被使用过的操作带来的 \(v\),还是新开一次操作,同时枚举它的对象,让它的 \(v\) 产生贡献。
\(f_{i, j}\) 意义不变,转移式:
第二个转移同时枚举了操作的标号、操作的位置。
这样的本质是什么呢,是操作直到后面生效时才会被区分。通过把贡献式拆成 \(a_i\) 和 \(v\) 的乘积,每一项最多只会涉及一次操作,这样就降下了枚举操作次数的复杂度。
注意到有一些操作直到最后都没有被区分,答案是 \(\sum f_{n, i} n^{m-i}\)。
#include <bits/stdc++.h>
const int mod = 1e9 + 7;
int main() {
int n, m;
modint v;
scanf("%d %d %d", &n, &m, &v);
std::vector<modint> a(n);
for (modint &x : a) scanf("%d", &x);
std::vector<modint> f(n + 1);
f[0] = 1;
for (int i = 0; i < n; i++) {
std::vector<modint> g(n + 1);
for (int j = 0; j <= i; j++) {
g[j] += f[j] * j * v;
g[j + 1] += f[j] * (i + 1) * (m - j) * v;
g[j] += f[j] * a[i];
}
f = g;
}
modint ans;
for (int i = 0; i <= m && i <= n; i++) {
ans += f[i] * qpow(n, m - i);
}
ans = ans / qpow(n, m);
printf("%d\n", ans);
return 0;
}
modint :
struct modint {
int x;
modint(int o = 0) { x = o; }
modint &operator=(int o) { return x = o, *this; }
modint &operator+=(modint o) {
return x = x + o.x >= mod ? x + o.x - mod : x + o.x, *this;
}
modint &operator-=(modint o) {
return x = x - o.x < 0 ? x - o.x + mod : x - o.x, *this;
}
modint &operator*=(modint o) { return x = 1ll * x * o.x % mod, *this; }
modint &operator^=(int b) {
modint a = *this, c = 1;
for (; b; b >>= 1, a *= a)
if (b & 1) c *= a;
return x = c.x, *this;
}
modint &operator/=(modint o) { return *this *= o ^= mod - 2; }
friend modint operator+(modint a, modint b) { return a += b; }
friend modint operator-(modint a, modint b) { return a -= b; }
friend modint operator*(modint a, modint b) { return a *= b; }
friend modint operator/(modint a, modint b) { return a /= b; }
friend modint operator^(modint a, int b) { return a ^= b; }
friend bool operator==(modint a, int b) { return a.x == b; }
friend bool operator!=(modint a, int b) { return a.x != b; }
bool operator!() { return !x; }
modint operator-() { return x ? mod - x : 0; }
bool operator<(const modint &b) const { return x < b.x; }
};
inline modint qpow(modint x, int y) { return x ^ y; }
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/solution-cf1842g.html