「PKUWC2018」猎人杀(概率+容斥+分治NTT)
Posted coldchair
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「PKUWC2018」猎人杀(概率+容斥+分治NTT)相关的知识,希望对你有一定的参考价值。
很有意思的一道题目。
直接去算这题话,因为分母会变,你会发现不管怎么样都要枚举顺序。
考虑把题目转换,变成分母不会变的,即对于一个已经删过的,我们不把它从分母中剔除,但是,每一次的选择需要一直选直到选了一个没有被删过的。
然后再考虑怎么计算,这时就可以容斥了:
1既然要最后删除,我们枚举一个集合S一定在它之后被删,其它的随意。
设(sw)为(sum_{iin S}w[i]),(W=sum_{i=1}^n w[i])
最后答案就是(sum_{S}(-1)^{|S|}sum_{i=0}^{∞}({W-sw-w[1] over W})^i*{w[1] over W})
(=sum_S (-1)^{|S|}{Wover sw+w[1]}*{w[1]over W})
(=sum_S (-1)^{|S|} {w[1] over sw+w[1]})
用一个分治NTT优化一下背包就好了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;
const int mo = 998244353;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
#define V vector<ll>
#define si size()
#define re resize
namespace ntt {
const int nm = 131072;
int r[nm]; ll w[nm], a[nm], b[nm];
void build() {
for(int i = 1; i < nm; i *= 2) {
w[i] = 1; ll v = ksm(3, (mo - 1) / 2 / i);
ff(j, 1, i) w[i + j] = w[i + j - 1] * v % mo;
}
}
void dft(ll *a, int n, int f) {
ff(i, 0, n) {
r[i] = r[i / 2] / 2 + (i & 1) * (n / 2);
if(i < r[i]) swap(a[i], a[r[i]]);
} ll b;
for(int i = 1; i < n; i *= 2) for(int j = 0; j < n; j += 2 * i) ff(k, 0, i)
b = a[i + j + k] * w[i + k], a[i + j + k] = (a[j + k] - b) % mo, a[j + k] = (a[j + k] + b) % mo;
if(f == -1) {
reverse(a + 1, a + n);
b = ksm(n, mo - 2);
ff(i, 0, n) a[i] = (a[i] + mo) * b % mo;
}
}
V operator * (V p, V q) {
int n0 = p.si + q.si - 1, n = 1;
while(n < n0) n *= 2;
ff(i, 0, n) a[i] = b[i] = 0;
ff(i, 0, p.si) a[i] = p[i];
ff(i, 0, q.si) b[i] = q[i];
dft(a, n, 1); dft(b, n, 1);
ff(i, 0, n) a[i] = a[i] * b[i] % mo;
dft(a, n, -1);
p.re(n0);
ff(i, 0, p.si) p[i] = a[i];
return p;
}
}
using ntt :: operator *;
const int N = 1e5 + 5;
int n, w[N];
V dg(int x, int y) {
if(x > y) {
V p; p.re(1); p[0] = 1;
return p;
}
if(x == y) {
V p; p.clear(); p.re(w[x] + 1);
p[0] = 1; p[w[x]] = -1;
return p;
}
int m = x + y >> 1;
return dg(x, m) * dg(m + 1, y);
}
int main() {
ntt :: build();
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &w[i]);
V p = dg(2, n);
ll ans = 0;
ff(i, 0, p.si) ans = (ans + p[i] * ksm(i + w[1], mo - 2) % mo * w[1]) % mo;
ans = (ans % mo + mo) % mo;
pp("%lld
", ans);
}
以上是关于「PKUWC2018」猎人杀(概率+容斥+分治NTT)的主要内容,如果未能解决你的问题,请参考以下文章