简单的题目描述往往有着不简单的解法…
要点分析
考虑一个EGF
第i项表示长度为i的最终状态为s的序列有多少个。
再考虑上面的EGF,第i项是每一位操作了偶数次的序列有多少个。
这两个都可以递推出来,只需要知道存 e v x e^{vx} evx的系数就可以了。
考虑如何把EGF转OGF:
设f,g分别是F,G对应的ogf.
设h是答案ogf,则有
h
(
x
)
g
(
x
)
=
f
(
x
)
h(x)g(x)=f(x)
h(x)g(x)=f(x)
现在答案为
h
′
(
1
)
h'(1)
h′(1),即为求
[
f
(
1
)
g
(
1
)
]
′
=
f
′
(
1
)
g
(
1
)
−
f
(
1
)
g
′
(
1
)
g
2
(
1
)
[\frac {f(1)} {g(1)}]'=\frac{f'(1)g(1)-f(1)g'(1)}{g^2(1)}
[g(1)f(1)]′=g2(1)f′(1)g(1)−f(1)g′(1)
但是f,g作为形式幂级数,发现把x=1带进去存在分母=0的情况。对形式幂级数一发乱搞通分,将分母移动到分子,然后上下可以把分母约去。
然后原函数值随便算,导函数的值看起来难算但实际上有那个为0的原先分母项的都不用考虑。所以直接线性或者带个log都可以。
不知道为什么我算出来就是答案的相反数…找不到原因。
几个新操作:
- 生成函数的题,答案不一定是某项系数。这题就是直接求生成函数(的导函数)值。
- 已知EGF求OGF的值,求出egf的e^vx系数就可以实现。
- 形式幂级数中的x事实上只是一个记号。讲究有没有意义、收不收敛本身就没有意义。只要能带进去算值,就可以得出期望的结果。
- 答案 * 恒等 = 好算的类答案 (意会一下)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define inv(x) ksm((x) % mo, mo-2)
using namespace std;
typedef long long ll;
const int N = 110, M = 100010 * 2, mo = 998244353;
int n, s[N];
ll P,p[N];
ll f[M], g[M], tmp[M];
ll Z = 50010;
ll sum, ny;
ll ksm(ll x,ll y) {
ll ret = 1; for(; y; y>>=1) {
if (y & 1) ret = ret * x % mo;
x = x * x % mo;
}
return ret;
}
ll val(ll *u) {
ll ret = u[Z + sum];
for(int i = - sum; i < sum; i++)
ret = ret * (1 - i * ny % mo) % mo;
return ret;
}
ll dao(ll *u) {
ll s = 1;
for(int i = - sum; i < sum; i++)
s = s * (1 - i * ny % mo) % mo;
ll ret = 0;
for(int i = - sum; i < sum; i++) {
ret = (ret + u[Z + i] * s % mo * inv(1 - i * ny) % mo) % mo;
}
for(int i = - sum; i < sum; i++) {
ret = (ret + u[Z + sum] * s % mo * inv(1 - i * ny) % mo) % mo;
}
return ret;
}
int main(){
freopen("a.in","r",stdin);
cin>>n;
for(int i = 1; i <= n; i++) scanf("%d",&s[i]);
for(int i = 1; i <= n; i++) scanf("%lld",&p[i]), sum+=p[i];
ny = inv(sum);
f[Z] = g[Z] = 1;
for(int i = 1; i <= n; i++) {
memset(tmp,0,sizeof tmp);
for(int j = Z - sum; j <= Z + sum; j++) {
tmp[j] = (j - p[i] >= 0 ? f[j - p[i]] : 0) + (s[i] ? -1 : 1) * f[j + p[i]];
tmp[j] %= mo;
}
memcpy(f, tmp, sizeof tmp);
memset(tmp,0,sizeof tmp);
for(int j = Z - sum; j <= Z + sum; j++) {
tmp[j] = (j - p[i] >= 0 ? g[j - p[i]] : 0) + g[j + p[i]];
tmp[j] %= mo;
}
memcpy(g, tmp, sizeof tmp);
}
ll ans = (dao(f) * val(g) % mo - dao(g) * val(f) % mo) % mo;
ans = ans * inv(val(g) * val(g)) % mo;
printf("%lld\n",((mo-ans)%mo+mo)%mo);
}