题解 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 。