CF1172C2 Nauuo and Pictures
前情提要:聪明猫跟金勾爷 lzy duel,输掉了……
大概想到能分开每个位置考虑,以及 \(\texttt{01}\) 分开,然后意识到不得不回宿舍了,没继续想了。
首先注意到对于整个序列 dp 实在是太奢侈了,根本没法设计状态,只能对每个位置考虑。
先想到一个暴力 dp。设 \(f^k_{x, s_0, s_1}\) 表示对于某一位考虑,自己、喜欢的、不喜欢的操作次数分别为 \(x,\ s_0,\ s_1\) 时,继续操作,当前位被操作次数的期望。
这个大概是 \(O(nm^3)\) 的,于是可以过掉 easy version。
还是有点浪费,这种多个对象之间关系的 dp 大多可以拆成许多独立的部分,这个也一样。
我们注意到实际上“在对应的部分操作 \(k\) 次,某个位置被操作次数的期望”、“全局操作 \(k\) 次,两部分之一被操作次数的期望”,这两部分是完全分开的,因为操作在单个对象内的体现是一致的,要么 \(+1\) 要么 \(-1\)。
先考虑“全局操作 \(k\) 次,两部分之一被操作次数的期望”。这个可以直接暴力 dp。设 \(f^k_{x}\) 表示一共操作 \(k\) 次,已经对喜欢的部分操作了 \(x\) 次,对喜欢的部分的操作的次数期望。复杂度 \(O(m^2)\)。
还有“在对应的部分操作 \(k\) 次,某个位置被操作次数的期望”。我 duel 的时候没想清楚这个。
lzy:我们大胆猜测,对一个部分操作 \(k\) 次,某个位置 \(x\) 和这个部分其他的位置 \(y\),它们被操作次数的期望是和权值成比例的。
具体怎么证 lzy 也没说,只说这挺好证的……
大概说说吧。归纳一下应该很好搞。
假如操作是 \(+1\),设:
表示两个数的权值为 \(x\) 和 \(y\) 的时候,再操作 \(k\) 次之后 \(x\) 的期望。
要证:
\(k = 0\) 显然满足。
感觉挺脱裤子放屁的,总之就是这样。
code:
// No mind to think.
//
// No will to break.
//
// No voice to cry suffering.
//
// Born of God and Void.
//
// You shall seal the blinding light that plagues their dreams.
//
// You are the Vessel.
//
// You are the Hollow Knight.
#ifdef N2
#define _GLIBCXX_DEBUG
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#define DO(...) __VA_ARGS__
#else
#define LOG(...) void(0)
#define DO(...) void(0)
#define NDEBUG
#endif
#define syncoff ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 2e5 + 10;
const int maxm = 3010;
using ll = long long;
ll Pow(ll a, ll b = mod - 2, ll mod = mod) {
ll res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod, b >>= 1;
}
return res;
}
int d;
int w[maxn];
int lk[maxn];
int s[2];
int n, m;
int f[maxm][maxm];
int F(int k, int d1) {
if(~f[k][d1]) return f[k][d1];
if(k == m) return f[k][d1] = d1;
int d0 = k - d1;
int w0 = (s[0] - d0 + mod) % mod;
int w1 = (s[1] + d1) % mod;
return f[k][d1] = ((ll)w0 * F(k + 1, d1) % mod + (ll)w1 * F(k + 1, d1 + 1) % mod) % mod * Pow((w0 + w1) % mod) % mod;
}
int main() {
syncoff;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> lk[i];
for(int i = 1; i <= n; i++) cin >> w[i];
for(int i = 1; i <= n; i++) {
s[lk[i]] += w[i];
if(s[lk[i]] >= mod) s[lk[i]] -= mod;
}
memset(f, -1, sizeof(f));
int d1 = F(0, 0);
int d0 = (m - d1 + mod) % mod;
LOG("%d %d\n", d1, d0);
for(int i = 1; i <= n; i++) {
if(lk[i]) {
cout << (w[i] + (ll)d1 * w[i] % mod * Pow(s[1]) % mod) % mod << '\n';
} else {
cout << (w[i] - (ll)d0 * w[i] % mod * Pow(s[0]) % mod + mod) % mod << '\n';
}
}
}