• 洛谷 P5162 WD与积木【多项式求逆】


    设f[i]为i个积木能堆出来的种类,g[i]为i个积木能堆出来的种类和

    [f[n]=sum_{i=1}^{n}C_{n}^{i}g[n-i] ]

    [g[n]=sum_{i=1}^{n}C_{n}^{i}f[n-i]+g[n] ]

    理解就是选出包含最后一个的块,然后剩下的按照之前的拼
    化简,设s为( frac{1}{n!} ),G为( frac{g[n]}{n!} ),F为( frac{fn]}{n!} ),把组合数拆开,变成卷积形式,然后化简就变成

    [F=frac{1}{1-S} ]

    [G=F*(F-1) ]

    用多项式求逆即可

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1000005,mod=998244353;
    int T,n=1e5+5,s[N],f[N],g[N],a[N],b[N],c[N],t[N],fac[N],inv[N],re[N],lm,bt,ans[N];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    int ksm(int a,int b)
    {
    	int r=1;
    	while(b)
    	{
    		if(b&1)
    			r=1ll*r*a%mod;
    		a=1ll*a*a%mod;
    		b>>=1;
    	}
    	return r;
    }
    void dft(int a[],int f)
    {
    	for(int i=0;i<lm;i++)
    		if(i<re[i])
    			swap(a[i],a[re[i]]);
    	for(int i=1;i<lm;i<<=1)
    	{
    		int wi=ksm(3,(mod-1)/(i*2));
    		if(f==-1)
    			wi=ksm(wi,mod-2);
    		for(int k=0;k<lm;k+=(i<<1))
    		{
    			int w=1,x,y;
    			for(int j=0;j<i;j++)
    			{
    				x=a[j+k];
    				y=1ll*a[i+j+k]*w%mod;
    				a[j+k]=(x+y)%mod;
    				a[i+j+k]=(x-y+mod)%mod;
    				w=1ll*w*wi%mod;
    			}
    		}
    	}
    	if(f==-1)
    	{
    		int ni=ksm(lm,mod-2);
    		for(int i=0;i<lm;i++)
    			a[i]=1ll*a[i]*ni%mod;
    	}
    }
    void clc(int len)
    {//cerr<<len<<endl;
    	if(len==0)
    	{
    		c[0]=ksm(s[0],mod-2);
    		return;
    	}
    	clc(len>>1);
    	for(bt=1;(1<<bt)<=len;bt++);
    	lm=(1<<bt);
    	for(int i=0;i<lm;i++)
    		re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
    	for(int i=0;i<len;i++)
    		t[i]=s[i];
    	dft(t,1);
    	dft(c,1);
    	for(int i=0;i<lm;i++)
    		c[i]=1ll*c[i]*(mod+2-1ll*c[i]*t[i]%mod)%mod;
    	dft(c,-1);
    	for(int i=len;i<=2*lm+1;i++)
    		c[i]=0;
    	for(int i=0;i<=2*lm+1;i++)
    		t[i]=0;
    }
    int main()
    {
    	n=1e5+5;
    	fac[0]=inv[0]=1;
    	for(int i=1;i<=n;i++)
    		fac[i]=1ll*fac[i-1]*i%mod;
    	inv[n]=ksm(fac[n],mod-2);
    	for(int i=n-1;i>=1;i--)
    		inv[i]=1ll*inv[i+1]*(i+1)%mod;
    	for(int i=1;i<=n;i++)
    		s[i]=mod-inv[i];
    	s[0]++;
    	for(bt=1;(1<<bt)<=2*n;bt++);
    	lm=(1<<bt);
    	clc(lm);
    	for(int i=1;i<=n;i++)
    		a[i]=b[i]=f[i]=c[i];
    	f[0]=a[0]=1,b[0]=0;
    	// for(int i=0;i<=10;i++)
    		// cerr<<f[i]<<" ";cerr<<endl;
    	for(bt=1;(1<<bt)<=2*n;bt++);
    	lm=(1<<bt);
    	for(int i=0;i<lm;i++)
    		re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
    	dft(a,1);
    	dft(b,1);
    	for(int i=0;i<lm;i++)
    		g[i]=1ll*a[i]*b[i]%mod;
    	dft(g,-1);
    	for(int i=1;i<=n;i++)
    		ans[i]=1ll*g[i]*ksm(f[i],mod-2)%mod;//,printf("%d
    ",ans[i]);
    	T=read();
    	while(T--)
    		printf("%d
    ",ans[read()]);
    	return 0;
    }
    
  • 相关阅读:
    操作系统
    OSI协议
    5、hadoop常见端口汇总
    20、Linux 常用命令ll失效
    java 图形化工具Swing 监听键盘输入字符触发动作getInputMap();getActionMap();
    java 图形化工具Swing 基本使用
    java 图形化小工具Abstract Window Toolit ImageIO缩放图片,添加水印
    java 图形化小工具Abstract Window Toolit 画笔 处理位图
    java 图形化小工具Abstract Window Toolit :画笔Graphics,画布Canvas(),弹球小游戏
    java 图形化小工具Abstract Window Toolit 菜单项
  • 原文地址:https://www.cnblogs.com/lokiii/p/11037968.html
Copyright © 2020-2023  润新知