• 题解 UOJ #102. 【集训队互测2015】ydc的奖金


    传送门

    调到我心态都快崩了,发现了板子的一堆问题


    【分析】

    对于第 \(i\) 个人,我们不妨假设它的得分 \(X_i\) 的概率分布函数为 \(F_i(x)=\bold{Pr}(X_i\leq x)\)

    假定我们取 \(X_i\) 落入一个极小的区间区间 \([x, x+\Delta x]\) 的概率来代替 \(X_i\) 取得 \(x\) 的概率,则根据题意,得到:

    \(\displaystyle \lim_{\Delta x\to 0}{F_i(x+\Delta x)-F_i(x)\over F_i(\Delta x)-F_i(0)}={\bold{Pr}(X_i=x)\over \bold{Pr}(X_i=0)}={f_i(x)\over f_i(0)}\)

    于是我们得到:\(\displaystyle {\text d\over \text dx}F_i(x)=k_i\cdot f_i(x)\) ,则 \(\displaystyle F_i(x)=k_i\cdot \int_{-\infty}^x f_i(x)\text dx\)

    考虑到随机变量在区间 \([0, 1]\) 内分布,故根据概率的归一性,有 \(\displaystyle F_i(1)=k_i\cdot \int_0^1 f_i(x)\text dx=1\) ,所以 \(\displaystyle k_i=(\int_0^1 f_i(x)\text dx)^{-1}\)

    从概率意义上说,\(f_i(x)\) 是随机变量 \(X_i\) 概率密度函数的一个倍数。


    我们考虑,若第 \(n\) 人的随机变量取值为 \(x\) 时,对答案的贡献如何计算。

    对于第 \(i\) 人,取得的数值比 \(x\) 小的概率为 \(F_i(x)\) ;而更大的为 \(1-F_i(x)\)

    那如何统计比 \(x\) 高的数量为 \(k(k\in[0,n-1])\) 的概率呢?

    我们考虑构造一个二维生成函数 \(F_i(x)+(1-F_i(x))y\),将他们累乘起来,\(y^k\) 的占位多项式系数即为比 \(x\) 高的数量为 \(k\) 的概率。

    而考虑第 \(n\) 人取 \(x\) 的概率同样用 \([x, x+\Delta x]\) 代替,同理取极限得到 \(\displaystyle {1\over k_n}f_n(x)\text dx\)

    于是,我们对 \([0, 1]\) 中无限多的 \(x\) 进行积分,得到 \(\displaystyle G(y)=\int_0^1 \prod_{i=1}^{n-1}[F_i(x)+(1-F_i(x))y]\cdot {1\over k_n}f_n(x)\text dx\)

    那么,\([y^k]G(y)\) 即为对 \(x\in[0, 1]\) ,有 \(k\) 人比第 \(n\) 人随机变量更大的概率。

    而有 \(k\) 人比第 \(n\) 人随机变量更大,即为第 \(n\) 人的排名为第 \(k+1\) 名。

    因此,答案为 \(\displaystyle \sum_{i=1}^n p_i\cdot [y^{i-1}]G(y)\)

    对于 \(G(y)\) 的求解,关键在于如何求出不带外层积分的函数 \(\displaystyle G(x, y)=\prod_{i=1}^{n-1}[F_i(x)+(1-F_i(x))y]\cdot {1\over k_n}f_n(x)\) 。很显然,这个问题可以由二维 FFT 解决。


    【代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define sz(a) (int)a.size()
    #define de(a) cout << #a <<" = "<<a<<endl
    #define dd(a) cout << #a <<" = "<<a<<" "
    #define rsz(a, x) (a.resize(x))
    typedef long long ll;
    
    constexpr int P=998244353;
    constexpr int LimBit=12, M=1<<LimBit<<1;
    inline int kpow(int a, int x, int p=P) { int ans=1; for(;x;x>>=1, a=(ll)a*a%p) if(x&1) ans=(ll)ans*a%p; return ans; }
    inline int exgcd(int a, int b, int &x, int &y) {
    	static int g;
    	return b?(exgcd(b, a%b, y, x), y-=a/b*x, g):(x=1, y=0, g=a);
    }
    inline int inv(int a, int p=P) {
    	static int x, y;
    	return exgcd(a, p, x, y)==1?(x<0?x+p:x):-1;
    }
    namespace Poly {
    	const int G=3;
    	struct vir {
    		int v;
    		vir(int v_=0):v(v_>=P?v_-P:v_) {}
    		inline vir operator + (const vir &x) const { return vir(v+x.v); }
    		inline vir operator - (const vir &x) const { return vir(v+P-x.v); }
    		inline vir operator * (const vir &x) const { return vir((ll)v*x.v%P); }
    
    		inline vir operator - () const { return vir(P-v); }
    		inline vir operator ! () const { return vir(inv(v)); }
    		inline operator int() const { return v; }
    	};
    	struct poly : public vector<vir> {
    		inline friend ostream& operator << (ostream& out, const poly &p) {
    			if(!p.empty()) out<<(int)p[0];
    			for(int i=1; i<sz(p); ++i) out<<" "<<(int)p[i];
    			return out;
    		}
    	};
    
    	int N, N_, rev[M];
    	vir invN, Inv[M], w[2][M];
    	inline void init() {
    		N_=-1;
    		Inv[1]=1;
    		for(int i=2; i<M; ++i)
    			Inv[i]=-vir(P/i)*Inv[P%i];
    	}
    	inline void work() {
    		if(N_==N) return ;
    		N_=N;
    		int d=__builtin_ctz(N);
    		vir x(kpow(G, (P-1)/N)), y=!x;
    		w[0][0]=w[1][0]=1;
    		for(int i=1; i<N; ++i) {
    			rev[i]=(rev[i>>1]>>1)|((i&1)<<(d-1));
    			w[0][i]=x*w[0][i-1], w[1][i]=y*w[1][i-1];
    		}
    		invN=!vir(N);
    	}
    
    	inline void FFT(vir a[M], int f) {
    		static auto make = [=](vir w, vir &a, vir &b) { w=w*a; a=b-w; b=b+w; };
    		for(int i=0; i<N; ++i) if(i<rev[i]) swap(a[i], a[rev[i]]);
    		for(int i=1; i<N; i<<=1)
    			for(int j=0, t=N/(i<<1); j<N; j+=i<<1)
    				for(int k=0, l=0; k<i; ++k, l+=t)
    					make(w[f][l], a[j+k+i], a[j+k]);
    		if(f) for(int i=0; i<N; ++i) a[i]=a[i]*invN;
    	}
    
    	vir p1[M], p0[M];
    	inline void get_mul(poly &a, poly &b, int na, int nb) {
    		for(N=1; N<na+nb-1; N<<=1);
    		for(int i=0; i<na; ++i) p1[i]=(int)a[i]; for(int i=na; i<N; ++i) p1[i]=0;
    		for(int i=0; i<nb; ++i) p0[i]=(int)b[i]; for(int i=nb; i<N; ++i) p0[i]=0;
    		work(); FFT(p1, 0); FFT(p0, 0);
    		for(int i=0; i<N; ++i) p1[i]=p1[i]*p0[i];
    		FFT(p1, 1);
    		rsz(a, na+nb-1); for(int i=0; i<sz(a); ++i) a[i]=p1[i];
    	}
    	inline void get_int(poly &f, poly &g, int C=0) {
    		int siz=sz(f);
    		rsz(g, siz+1);
    		for(int i=siz; i; --i) g[i]=f[i-1]*Inv[i];
    		g[0]=C;
    	}
    
    	struct mat : public vector<poly> {
    		void ex_resize(int n, int m) {
    			this->resize(n);
    			for(auto &e : *this)
    				rsz(e, m);
    		}
    	};
    	vir m0[1024][M], m1[1024][M];
    	inline void get_mul_2D(mat &f, mat &g) {
    		static int nfx, nfy, ngx, ngy;
    		static int Nx, Ny, sx, sy;
    		nfx=sz(f); for(int i=nfy=0; i<nfx; ++i) nfy=max(nfy, sz(f[i]));
    		ngx=sz(g); for(int i=ngy=0; i<ngx; ++i) ngy=max(ngy, sz(g[i]));
    		sx=nfx+ngx-1; sy=nfy+ngy-1;
    		for(Nx=1; Nx<sx; Nx<<=1);
    		for(Ny=1; Ny<sy; Ny<<=1);
    
    		N=Nx; work();
    		for(int j=0; j<nfy; ++j) {
    			for(int i=0; i<N; ++i) p1[i]=0;
    			for(int i=0; i<nfx; ++i)
    				if(sz(f[i])>j)
    					p1[i]=f[i][j];
    			FFT(p1, 0);
    			for(int i=0; i<Nx; ++i) m1[i][j]=p1[i];
    		}
    		for(int j=nfy; j<Ny; ++j)
    			for(int i=0; i<Nx; ++i)
    				m1[i][j]=0;
    		for(int j=0; j<ngy; ++j) {
    			for(int i=0; i<N; ++i) p0[i]=0;
    			for(int i=0; i<ngx; ++i)
    				if(sz(g[i])>j)
    					p0[i]=g[i][j];
    			FFT(p0, 0);
    			for(int i=0; i<Nx; ++i) m0[i][j]=p0[i];
    		}
    		for(int j=ngy; j<Ny; ++j)
    			for(int i=0; i<Nx; ++i)
    				m0[i][j]=0;
    
    		N=Ny; work();
    		for(int i=0; i<Nx; ++i) FFT(m1[i], 0);
    		for(int i=0; i<Nx; ++i) FFT(m0[i], 0);
    
    		for(int i=0; i<Nx; ++i)
    			for(int j=0; j<Ny; ++j)
    				m1[i][j]=m1[i][j]*m0[i][j];
    
    		for(int i=0; i<Nx; ++i) FFT(m1[i], 1);
    		N=Nx; work();
    		f.ex_resize(sx, sy);
    		for(int j=0; j<sy; ++j) {
    			for(int i=0; i<Nx; ++i) p1[i]=m1[i][j];
    			FFT(p1, 1);
    			for(int i=0; i<sx; ++i) f[i][j]=p1[i];
    		}
    		for(auto &p : f) {
    			int siz=sz(p);
    			while(siz>1&&p[siz-1].v==0)
    				--siz;
    			rsz(p, siz);
    		}
    	}
    }
    using Poly::mat;
    using Poly::poly;
    using Poly::vir;
    using Poly::Inv;
    
    inline vir get_value(const poly &p) {
    	vir x;
    	for(int i=0; i<sz(p); ++i)
    		x=x+p[i]*Inv[i+1];
    	return x;
    }
    
    constexpr int MAXN=512;
    mat f[MAXN];
    poly tmp;
    vir p[MAXN], prod;
    int n;
    void merge(int l, int r) {
    	if(l==r)
    		return ;
    	int mid=l+r>>1;
    	merge(l, mid);
    	merge(mid+1, r);
    	Poly::get_mul_2D(f[r], f[mid]);
    }
    inline void work() {
    	merge(1, n);
    	vir x;
    	for(int i=sz(f[n])-1; i>=0; --i)
    		x=x+get_value(f[n][i])*p[i];
    	cout<<(int)(x*!prod);
    }
    inline void init() {
    	Poly::init();
    	cin>>n;
    	for(int i=0, v; i<n; ++i)
    		cin>>v, p[i]=v;
    	
    	int t;
    	vir x;
    	prod=1;
    	for(int i=1; i<n; ++i) {
    		cin>>t;
    		rsz(tmp, t);
    		for(int j=0, v; j<t; ++j)
    			cin>>v, tmp[j]=v;
    		x=get_value(tmp);
    		prod=prod*x;
    		Poly::get_int(tmp, tmp);
    		rsz(f[i], 2);
    		f[i][0]=tmp;
    		for(auto &e : tmp)
    			e=-e;
    		tmp[0]=tmp[0]+x;
    		f[i][1]=tmp;
    	}
    	cin>>t;
    	rsz(tmp, t);
    	for(int i=0, v; i<t; ++i)
    		cin>>v, tmp[i]=v;
    	prod=prod*get_value(tmp);
    	rsz(f[n], 1);
    	f[n][0]=tmp;
    }
    int main() {
    	ios::sync_with_stdio(0);
    	cin.tie(0); cout.tie(0);
    	init();
    	work();
    	cout.flush();
    	return 0;
    }
    

    目前 rank1 ,领先第二名近 700 ms 。

  • 相关阅读:
    New-SAN-FENG-YUN-三
    San丰-Cloud
    SpringBoot+MySQL+MyBatis+Shiro+AdminLTE
    SanFeng-Clound
    SanFengClound
    传奇音乐设置
    热血传奇GOM引擎问题集锦
    app测试
    接口测试
    题目
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/16340151.html
Copyright © 2020-2023  润新知