zoukankan      html  css  js  c++  java
  • LOJ6402 yww 与校门外的树

    yww 与校门外的树

    二中的校门外有一排树,一共 (n) 棵。每棵树的高度为 ([0,1]) 之间的随机小数。每棵树上都有一个苹果。

    zjt 把这 (n) 棵树从左到右编号为 (1sim n)。zjt 还会在某些树之间挂上绳索。设第 (i) 棵树的高度为 (a_i) 。如果对于两棵树 (i,j) 满足 (i<j)(a_i<a_j) ,那么 zjt 就会在第 (i) 棵树与第 (j) 棵树之间挂上一条绳索。这些绳索是双向的。

    这时,有很多猴子路过了这里,你可以认为是 (n) 只,或是 (2n) 只,或是 (infty) 只。这些猴子会依次选择一棵有苹果的树(如果所有树上都没有苹果就不选),然后把这棵树以及可以通过绳索去到的其他树上的苹果全部摘下来。如果一只猴子摘下来了 (x) 个苹果,那么猴群的团结度就会乘以 (x) 。猴群的初始团结度为 (1) 。如果一只猴子没有摘到苹果,那么他就会离开猴群,所以不会影响团结度。

    猴王想知道猴群的期望团结度是多少。请你帮帮他。

    设答案为 (s) ,显然 (s imes n!) 是一个整数。所以你只需要告诉他 (mathit{ans}=(s imes n!)mod 998244353) 的值 。

    对于 (100\%) 的数据:(1leq nleq 5 imes 10^5)

    题解

    https://jklover.hs-blog.cf/2020/06/17/Loj-6402-yww-与校门外的树/

    多项式求逆.

    首先这个随机过程可以等价于随机出了一个 (1sim n) 的排列,需要对每个排列的答案求和.

    不难发现,各个连通块是一段连续的区间,且两个相邻的连通块之间一定是左侧的最小值大于右侧的最大值.

    (F(x)) 表示长度为 (i) 的排列形成一个连通块的 OGF, 若干个这样的结构会组合成一个排列,且合并时顺序固定.

    那么设 (P(x)=sum i!x^i​) ,则有 (frac{1}{1-F(x)}=P​) ,得出 (F(x)=1-frac{1}{P(x)}​) .

    考虑如何计算答案,只需要把贡献放入 (F​(x)) 的每一项中,再用若干个结构卷起来组合成排列即可.

    (G(x)=sum f_1cdot icdot x^i) ,则 ([x^n]frac{1}{1-G(x)}) 即为所求.

    需要实现多项式乘法及求逆,时间复杂度 (O(nlog n)) .

    CO int N=1<<20;
    int omg[2][N],rev[N];
    int fac[N],inv[N],ifac[N];
    
    void NTT(poly&a,int dir){
    	int lim=a.size(),len=log2(lim);
    	for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    	for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=1;i<lim;i<<=1)
    		for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
    			int t=mul(omg[dir][N/(i<<1)*k],a[j+i+k]);
    			a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
    		}
    	if(dir){
    		int ilim=fpow(lim,mod-2);
    		for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
    	}
    }
    poly operator~(poly f){
    	int n=f.size();
    	poly g(1,fpow(f[0],mod-2));
    	f.resize(1<<(int)ceil(log2(n)));
    	for(int lim=2;lim<2*n;lim<<=1){
    		poly h(f.begin(),f.begin()+lim);
    		h.resize(lim<<1),NTT(h,0);
    		g.resize(lim<<1),NTT(g,0);
    		for(int i=0;i<lim<<1;++i) g[i]=mul(2+mod-mul(h[i],g[i]),g[i]);
    		NTT(g,1),g.resize(lim);
    	}
    	return g.resize(n),g;
    }
    
    int main(){
    	omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
    	omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
    	fac[0]=fac[1]=1;
    	inv[0]=inv[1]=1;
    	ifac[0]=ifac[1]=1;
    	for(int i=2;i<N;++i){
    		omg[0][i]=mul(omg[0][i-1],omg[0][1]);
    		omg[1][i]=mul(omg[1][i-1],omg[1][1]);
    		fac[i]=mul(fac[i-1],i);
    		inv[i]=mul(mod-mod/i,inv[mod%i]);
    		ifac[i]=mul(ifac[i-1],inv[i]);
    	}
    	int n=read<int>();
    	poly f=~poly(fac,fac+n+1);
    	f[0]=add(1,mod-f[0]);
    	for(int i=1;i<=n;++i) f[i]=mod-f[i];
    	f[0]=add(1,mod-mul(0,f[0]));
    	for(int i=1;i<=n;++i) f[i]=mod-mul(i,f[i]);
    	f=~f;
    	printf("%d
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    可视化工具Grafana:简介及安装
    数据采集工具Telegraf:简介及安装
    怒怼某些自媒体培训机构,吃相不要太难看了!!!
    时序数据库InfluxDB:简介及安装
    jmeter(二十五)linux环境运行jmeter并生成报告
    Linux:CentOS7.4新建用户并授权
    服务端监控工具:Nmon使用方法
    Locust:简介和基本用法
    Quant Finance Master’s Guide 2020
    数据科学入门前需要知道的10件事
  • 原文地址:https://www.cnblogs.com/autoint/p/13195242.html
Copyright © 2011-2022 走看看