• 「PKUWC2018」猎人杀(概率+容斥+分治NTT)


    https://loj.ac/problem/2541

    很有意思的一道题目。

    直接去算这题话,因为分母会变,你会发现不管怎么样都要枚举顺序。

    考虑把题目转换,变成分母不会变的,即对于一个已经删过的,我们不把它从分母中剔除,但是,每一次的选择需要一直选直到选了一个没有被删过的。

    然后再考虑怎么计算,这时就可以容斥了:
    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);
    }
    
  • 相关阅读:
    CDB命令方式创建和删除
    cdb和pdb的启停
    python 读取blob
    c# 读取blob数据
    python 为什么没有自增自减符
    程序异常重启代码
    便捷辅助开发工具
    正则表达式带例子详解
    名语中看代码
    c# 画一个报告
  • 原文地址:https://www.cnblogs.com/coldchair/p/12620161.html
Copyright © 2020-2023  润新知