• #514. 【UR #19】通用测评号(EGF初涉)


    题目描述


    EGF

    普通生成函数(OGF)(F(x)=sum a_ix^i)

    对应的指数型生成函数(EGF)(G(x)=sum frac{a_ix^i}{i!})

    用于解决组合问题,两个指数型生成函数相乘时

    (A(x)B(x)=sum a_ib_jfrac{x^{i+j}}{i!j!}=sum inom{i+j}{i}a_ib_jfrac{x^{i+j}}{(i+j)!}),即组合时会乘上一个组合数(i+j,j)

    简单应用:

    证明(sum i(n-i)inom{n}{i}=2^{n-2}n(n-1))

    (sum frac{ix^i}{i!}=xsum_{i>=1} frac{x^i}{i!}=xe^x)

    所以原式=([x^n]x^2e^{2x}=[x^n]sum{frac{2^ix^{i+2}}{i!}}),提出来就是(frac{2^{n-2}x^n}{(n-2)!}),转回OGF即为(2^{n-2}n(n-1)x^n)

    题解

    膜lk:https://qaq-am.com/UOJ514/#comment-18

    特地用黑体标出来误导的屑(

    由于考虑了这个所以只想到了n^4log的dp+FFT,其实把限制去掉和原问题等价

    证明:对于当前的一种状态,设选到>=a的概率为p,加上不选的限制后的答案为s

    那么去掉限制之后的答案为((1-p)s+p(1-p)s+p^2(1-p)s+...)

    求和等于((1-p)frac{p^infty -1}{p-1}=(1-p)frac{1}{1-p}=1),因此贡献不变

    最后一个放的舱一定为b,考虑枚举这个舱并计算其他>=a的贡献

    因此要乘上n(n-1),但是最后一步的概率是1/n,所以实际乘的是n-1

    (S_i=frac{(frac{x}{n})^i}{i!}),由于长度没有上限了,所以实际求的是

    ((n-1)(e^{frac{x}{n}}-sum_{i<a}S_i)(e^{frac{x}{n}}-sum_{i<b}S_i)^{n-2}S_{b-1})

    的OGF(F(x))的所有项之和,即(F(1))

    把二项式拆开,变成求若干(e^{ax}frac{x^b}{b!})的OGF的F(1)

    (e^{ax}frac{x^b}{b!}=sum frac{a^ix^{i+b}}{b!i!}=sum inom{i+b}{b}frac{a^ix^{i+b}}{(i+b)!})

    所以OGF为(F(x)=sum inom{i+b}{b}a^ix^{i+b}=frac{x^b}{(1+ax)^{b+1}})

    直接求即可,多项式项数为na,二项式展开为n,所以时间是(O(n^2alog(na)))

    简单卡常+register即可

    code

    998244353的模数有3和114514

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define C(n,m) (jc[n]*Jc[m]%998244353*Jc[(n)-(m)]%998244353)
    #define ll long long
    #define mod 998244353
    #define Mod 998244351
    #define G 114514
    //#define file
    using namespace std;
    
    ll jc[62501],Jc[62501],ww[62501],p[62501],a[65536],b[65536],c[65536],d[65536],w[17][65536],W[17][65536],ans,Ans,s,S;
    int a2[65536],m,n,A,B,i,j,k,l,N,N2,len;
    
    ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
    void init()
    {
    	ll w,w2,W,W2;
    	
    	jc[0]=jc[1]=Jc[0]=Jc[1]=ww[1]=p[0]=1;
    	fo(i,2,62500) ww[i]=mod-ww[mod%i]*(mod/i)%mod,jc[i]=jc[i-1]*i%mod,Jc[i]=Jc[i-1]*ww[i]%mod;
    	fo(i,1,62500) p[i]=p[i-1]*ww[n]%mod;
    	fo(i,0,N-1)
    	{
    		j=i,k=0;
    		fo(l,1,len)
    		k=k*2+(j&1),j>>=1;
    		a2[i]=k;
    	}
    	
    	l=2;k=1;
    	fo(i,1,len)
    	{
    		w2=qpower(G,(mod-1)/l),W2=qpower(G,(mod-1)-(mod-1)/l);w=W=1;
    		fo(j,0,k-1) ::w[i][j]=w,::W[i][j]=W,w=w*w2%mod,W=W*W2%mod;
    		l<<=1;k<<=1;
    	}
    }
    void dft(ll *a,int tp)
    {
    	static ll A[65536];
    	register int i,j,k,l,S=N,s1=2,s2=1;
    	ll u,v;
    	
    	fo(i,0,N-1) A[a2[i]]=a[i];
    	memcpy(a,A,N*8);
    	
    	fo(i,1,len)
    	{
    		S>>=1;
    		fo(j,0,S-1)
    		{
    			fo(k,0,s2-1)
    			{
    				u=a[j*s1+k],v=a[j*s1+k+s2]*((tp==1)?w[i][k]:W[i][k]);
    				a[j*s1+k]=(u+v)%mod;
    				a[j*s1+k+s2]=(u-v)%mod;
    			}
    		}
    		s1<<=1,s2<<=1;
    	}
    }
    void Mul(ll *a,ll *b) {int i;fo(i,0,N-1) a[i]=a[i]*b[i]%mod;}
    void turn(ll *a) {int i;fo(i,0,N-1) a[i]=a[i]*N2%mod;}
    void mul(ll *a,ll *b)
    {
    	static ll c[65536];
    	int i;
    	
    	memcpy(c,b,N*8);
    	dft(a,1),dft(c,1);
    	Mul(a,c);
    	dft(a,-1);
    	turn(a);
    }
    
    ll js(ll a,ll b) {return qpower(1-a,(mod-1)-(b+1));}
    void work()
    {
    	fo(i,0,A-1) a[i]=-Jc[i]*p[i]%mod;b[B-1]=Jc[B-1]*p[B-1]%mod,dft(a,1),dft(b,1),Mul(b,a);
    	memset(a,0,sizeof(a));
    	a[B-1]=Jc[B-1]*p[B-1]%mod,dft(a,1);
    	fo(i,0,B-1) c[i]=-Jc[i]*p[i]%mod;dft(c,1);
    	
    	fo(i,0,n-2)
    	{
    		Ans=0;
    		memcpy(d,a,N*8),dft(d,-1),turn(d),s=1,S=qpower(1-ww[n]*(n-1-i)%mod,Mod);
    		fo(j,0,m) s=s*S%mod,Ans=(Ans+s*(d[j]*jc[j]%mod))%mod;
    		memcpy(d,b,N*8),dft(d,-1),turn(d),s=1,S=qpower(1-ww[n]*(n-2-i)%mod,Mod);
    		fo(j,0,m) s=s*S%mod,Ans=(Ans+s*(d[j]*jc[j]%mod))%mod;
    		
    		ans=(ans+Ans*C(n-2,i))%mod;
    		if (i<n-2) Mul(a,c),Mul(b,c);
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("uoj514.in","r",stdin);
    	#endif
    	
    	scanf("%d%d%d",&n,&A,&B),len=ceil(log2(n*A+1)),N=qpower(2,len),N2=qpower(N,Mod),m=n*A;
    	if (n==1) {printf("1
    ");return 0;}
    	init();
    	work();
    	ans=(ans+mod)%mod;
    	printf("%lld
    ",ans*(n-1)%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    七.贪心算法
    六。二叉树
    从git指定commit拉分支
    二分法
    mysql 解决生僻字,特殊字符插入失败
    MYSQL性能优化以及建议
    PDF快捷键
    GC 核心关注点都在这里
    R语言载入包时报错:Error: 程辑包‘survival’没有名字空间
    Centos buff/cache过高
  • 原文地址:https://www.cnblogs.com/gmh77/p/13308677.html
Copyright © 2020-2023  润新知