zoukankan      html  css  js  c++  java
  • 6508. 【GDOI2020模拟03.11】我的朋友们(多项式求逆、分治NTT)

    题目描述


    多项式求逆

    第一次写就是这么毒瘤的题目

    已知

    (A(x)B(x)equiv 1(mod;x^n))

    要求

    (A(x)C(x)equiv 1(mod;x^{2n}))

    两式相减可得

    (A(x)(B(x)-C(x))equiv 1(mod;x^{n}))

    (B(x)-C(x)equiv 1(mod;x^{n}))

    平方一下

    (B^2(x)+C^2(x)-2B(x)C(x)equiv 0(mod;x^{2n})),因为x^0~x^2n拆分后一定有一个在n以内的

    两边同乘A(x)

    (A(x)B^2(x)+C(x)-2B(x)equiv 0(mod;x^{2n}))

    (C(x)equiv 2B(x)-A(x)B^2(x)(mod;x^{2n}))

    虽然做了log n次乘法,但n的总和还是n级别的,所以还是(O(n log n))

    分治FFT/NTT

    一般形式(本题与此无关):

    (f(i+j)=sum{f(i)*g(j)})

    cdq即可,log^2

    题解

    期望的一般算法:计算以某个状态为起点到终点的期望步数

    设f[i]表示从i开始的答案,Pi(x)表示在滑块[i,i+L-1]中的期望多项式,其中x^k表示有k个不合法

    那么可得

    (f[i]=sum_{j=0}^{L}{[x^j]P_i(x)f[i+j]})

    解方程可得

    (f[i]=frac{1}{1-[x^0]P_i(x)}sum_{j=1}^{L}{P_i(x)f[i+j]})

    不好算,所以把数组p翻转,变成(Pi(x)变成[i-L+1,i]的期望)

    (f[i]=frac{1}{1-[x^0]P_i(x)}sum_{j=1}^{L}{P_i(x)f[i-j]})

    接下来开始操♂作,定义

    (P[i]=p_ix+(1-p_i))(分清楚小括号和中括号),若i<1则P[i]=1

    (P_i(x)=prod_{i-L+1}^{i}{P[i]})

    (F_i(x)=sum_{j<=i}{x^j*f(j)})

    (S_i(x)=prod_{j<=i}{P[j]})

    (G[x][y]=prod_{i=y-L+1}^{x}{P[i]}=S_x(x)/S_{y-L}(x))

    (这里拓展了一下G的定义,为了方便之后的计算)

    (F[x][y]=F_{x-1}(x)*G[x][y])

    如果能求出每个F[x][x],那么([x^x]F[x][x])的系数就是(f[x])字母不够用意会一下

    (F[1][n]=0)(G[1][n]=S_1(x)/S_{n-L+1}(x)),直接乘会爆掉所以这里也要分治NTT

    向下分治,设m=(x+y)/2

    左半边:

    (G[x][m]=G[x][y]*prod_{i=m-L+1}^{y-L}{P[i]}=G[x][y]*prod_{i=m+1}^{y}{P[i-L]})

    (F[x][m]=F_{x-1}(x)*G[x][m]=F_{x-1}(x)*G[x][y]*prod_{i=m+1}^{y}{P[i-L]})

    (=F[x][y]*prod_{i=m+1}^{y}{P[i-L]})

    有可能i-L<1,但是可以发现这样f必然为0,所以可以把P设为1

    右半边:

    (G[m+1][y]=G[x][y]*prod_{i=x+1}^{m+1}{P[i]}=G[x][y]*prod_{i=x}^{m}{P[i+1]})

    (F[m+1][y]=F_{m}(x)*G[m+1][y]=F_{m}(x)*G[x][y]*prod_{i=x}^{m}{P[i+1]})

    为了方便接下来的操作,需要把Fm(x)的系数限制到x~y范围内

    (=F_{m}(x)*G[x][y]*prod_{i=x}^{m}{P[i+1]}-F_{x-1}(x)*G[x][y]*prod_{i=x}^{m}{P[i+1]}+前面那一坨)

    (=(F_{m}(x)-F_{x-1}(x))*G[x][y]*prod_{i=x}^{m}{P[i+1]}+F[x][y]*prod_{i=x}^{m}{P[i+1]})

    (=F[x][y]*prod_{i=x}^{m}{P[i+1]}+(F_{m}(x)-F_{x-1}(x))*G[m+1][y])

    看似时间复杂度不变,但实际上F只需要保留以x^y结尾的2(y-x+1)项,G只用保留前(y-x+1)项即可,剩余的不会对新的区间产生影响

    因为最终只需要x^x

    还有一个要注意的,乘到F里的G[m+1][y]要保留(y-x+1)项

    关键在于怎么实现,只可意会不可言传

    一个比较方便的写法是写一个 把A(x)的一段乘上B(x)的一段后把某一段(删掉开头若干项)丢到C(x)上 的函数,要仔细考虑具体删掉多少项

    极其难写+卡时间,写之前做好心理准备

    code

    我相信比expln之类的要难写的多(虽然还没学)

    #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 max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define mod 998244353
    #define Mod 998244351
    #define ll long long
    #define G 3
    #define file
    using namespace std;
    
    ll aa[262144],bb[262144],bb2[262144],bb3[262144],cc[262144],A[262144],p[262144],p1[4194304],p2[4194304]; //p1=i-l p2=i+1
    ll f[8388608],g[4194304],a[8388608],b[8388608],c[262144],ans[262144],P[262144]; //f=F g=G ans=f
    int bg[262144],ed[262144],bg1[262144],ed1[262144],bg2[262144],ed2[262144],A2[19][262144],len2[262145],n2[262145],n3[262145],W1[19],W2[19],n,L,I,J,i,j,k,l,s,s2,N,N2,len,tot,tot1,tot2;
    
    void look(ll *a,int x,int y)
    {
    	int i;
    	fd(i,y,x) cout<<(a[i]+mod)%mod<<" ";cout<<endl;
    }
    
    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 dft(ll *a,int type,int N,int len)
    {
    	int i,j,k,l,S=N,s1=2,s2=1;
    	ll w,W,u,v;
    	
    	fo(i,0,N-1) A[A2[len][i]]=a[i];
    	memcpy(a,A,N*8);
    	
    	fo(i,1,len)
    	{
    		S>>=1;
    		w=(type==1)?W1[i]:W2[i];
    		
    		fo(j,0,S-1)
    		{
    			W=1;
    			fo(k,0,s2-1)
    			{
    				u=a[j*s1+k];
    				v=a[j*s1+k+s2]*W;
    				
    				a[j*s1+k]=(u+v)%mod;
    				a[j*s1+k+s2]=(u-v)%mod;
    				
    				W=W*w%mod;
    			}
    		}
    		
    		s1<<=1,s2<<=1;
    	}
    }
    
    void mul(ll *x,ll *y,int n,int m)
    {
    	int i,j,k,l,N,N2,len;
    	
    	len=len2[n+m];N=n2[n+m];N2=n3[n+m];
    	
    	if (n<m)
    	fo(i,n,m) x[i]=0;
    	else
    	fo(i,m,n) y[i]=0;
    	fo(i,max(n,m),N-1) x[i]=y[i]=0;
    	memcpy(bb3,y,N*8);
    	
    	dft(x,1,N,len);
    	dft(bb3,1,N,len);
    	fo(i,0,N-1) x[i]=x[i]*bb3[i]%mod;
    	dft(x,-1,N,len);
    	fo(i,0,N-1) x[i]=x[i]*N2%mod;
    }
    void Mul(ll *x,ll *y,ll *z,int X1,int X2,int Y1,int Y2,int Z1,int Z2,int st)
    {
    	int i;
    	
    	fo(i,X1,X2) aa[i-X1]=x[i];
    	fo(i,Y1,Y2) bb[i-Y1]=y[i];
    	mul(aa,bb,X2-X1+1,Y2-Y1+1);
    	fo(i,Z1,Z2) z[i]=aa[i-Z1+st];
    }
    
    void ny(ll *a,int n)
    {
    	int i,j,k,l;
    	
    	cc[0]=qpower(a[0],Mod);
    	for (i=2; i<=n; i*=2)
    	{
    		memcpy(bb2,a,i*8);
    		
    		mul(bb2,cc,i,i);mul(bb2,cc,i,i);
    		fo(j,0,i+i-1)
    		bb2[j]=(2*cc[j]-bb2[j])%mod;
    		
    		memcpy(cc,bb2,i*8);
    	}
    	memcpy(a,cc,n*8);
    }
    
    void work(int t,int x,int y)
    {
    	int i,mid=(x+y)/2;
    	
    	if (x==y)
    	{
    		bg[t]=tot+1;ed[t]=tot+2;
    		
    		if (x>L)
    		p1[tot+1]=1-p[x-L],p1[tot+2]=p[x-L];
    		else
    		p1[tot+1]=1,p1[tot+2]=0;
    		if (x<n)
    		p2[tot+1]=1-p[x+1],p2[tot+2]=p[x+1];
    		else
    		p2[tot+1]=1,p2[tot+2]=0;
    		
    		tot+=2;
    		return;
    	}
    	
    	work(t*2,x,mid);
    	work(t*2+1,mid+1,y);
    	
    	bg[t]=tot+1;ed[t]=tot+(y-x+1)+1;
    	Mul(p1,p1,p1,bg[t*2],ed[t*2],bg[t*2+1],ed[t*2+1],bg[t],ed[t],0);
    	Mul(p2,p2,p2,bg[t*2],ed[t*2],bg[t*2+1],ed[t*2+1],bg[t],ed[t],0);
    	tot+=(y-x+1)+1;
    }
    
    void Work(int t,int x,int y)
    {
    	int i,mid=(x+y)/2;
    	
    	if (x==y)
    	{
    		if (x>=L)
    		ans[x]=(f[bg1[t]+1]+1)*qpower(1-P[x],Mod)%mod;
    		return;
    	}
    	
    	bg2[t*2]=tot2+1;ed2[t*2]=tot2+(mid-x+1);tot2+=mid-x+1;
    	Mul(g,p1,g,bg2[t],ed2[t],bg[t*2+1],ed[t*2+1],bg2[t*2],ed2[t*2],0);
    	
    	bg1[t*2]=tot1+1;ed1[t*2]=tot1+min(n+1,2*(mid-x+1));tot1+=min(n+1,2*(mid-x+1));
    	Mul(f,p1,f,bg1[t],ed1[t],bg[t*2+1],ed[t*2+1],bg1[t*2],ed1[t*2],max(0,2*x-mid-1)-max(0,2*x-y-1));
    	Work(t*2,x,mid);
    	
    //	---
    	
    	bg2[t*2+1]=tot2+1;ed2[t*2+1]=tot2+(y-mid);tot2+=y-mid;
    	Mul(g,p2,a,bg2[t],ed2[t],bg[t*2],ed[t*2],bg2[t],ed2[t],0); //Ïȱ£Áôy-x+1Ïî
    	fo(i,0,y-mid-1) g[bg2[t*2+1]+i]=a[bg2[t]+i];
    	
    	bg1[t*2+1]=tot1+1;ed1[t*2+1]=tot1+min(n+1,2*(y-mid));tot1+=min(n+1,2*(y-mid));
    	Mul(f,p2,b,bg1[t],ed1[t],bg[t*2],ed[t*2],bg1[t*2+1],ed1[t*2+1],max(0,2*mid-y+1)-max(0,2*x-y-1));
    	fo(i,x,mid) c[i]=ans[i];
    	Mul(c,a,a,x,mid,bg2[t],ed2[t],bg1[t*2+1],ed1[t*2+1],max(0,2*mid-y+1)-x);
    	
    	fo(i,bg1[t*2+1],ed1[t*2+1]) f[i]=(a[i]+b[i])%mod;
    	Work(t*2+1,mid+1,y);
    }
    
    int main()
    {
    	freopen("friends.in","r",stdin);
    	#ifdef file
    	freopen("friends.out","w",stdout);
    	#endif
    	
    	I=2;J=1;s=2;len2[1]=1;n2[1]=2;n3[1]=499122177;
    	fo(len,0,18)
    	{
    		if (len<18)
    		W1[len+1]=qpower(G,(mod-1)/s),W2[len+1]=qpower(W1[len+1],Mod);
    		
    		s2=qpower(s,Mod);
    		fo(i,0,J-1)
    		{
    			if (I<=262144)
    			len2[I]=len+1,n2[I]=s,n3[I]=s2,++I;
    			
    			j=i;k=0;
    			fo(l,1,len)
    			k=(k<<1)+(j&1),j>>=1;
    			
    			A2[len][i]=k;
    		}
    		J*=2;s=s*2;
    	}
    	
    	scanf("%d%d",&n,&L);
    	fd(i,n,1)
    	{
    		scanf("%d%d",&p[i],&j);
    		p[i]=p[i]*qpower(j,Mod)%mod;
    	}
    	P[L]=1;
    	fo(i,1,L) P[L]=P[L]*(1-p[i])%mod;
    	fo(i,L+1,n) P[i]=P[i-1]*(1-p[i])%mod*qpower(1-p[i-L],Mod)%mod;
    	
    	work(1,1,n);
    	
    	tot1=n+1;bg1[1]=1;ed1[1]=n+1;
    	tot2=n+1;bg2[1]=1;ed2[1]=n;
    	a[1]=p[1],a[0]=1-p[1];
    	fo(i,0,n)
    	b[i]=p1[bg[1]+i];
    	N=pow(2,ceil(log2(n+1)));
    	ny(b,N);
    	Mul(a,b,g,0,1,0,N-1,1,n,0);
    	
    	Work(1,1,n);
    	
    	printf("%lld
    ",(ans[n]+mod)%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    出售几个闲置的玉米
    竞价账户时好时坏怎样分析找到原因?
    两行代码轻松搞定网页自动刷新,简单,实用。
    BCompare文件对比神器 工程师 开发必备工具之一
    关于 Apache 屏蔽 IP 地址
    一段 JavaScript 实现禁止用户打开控制台与鼠标右键查看源码
    Apache使用.htaccess防盗链禁止用户下载
    HTML5下video右键禁用-禁止右键下载视频
    python装饰器
    部署nginx支持lua
  • 原文地址:https://www.cnblogs.com/gmh77/p/12535146.html
Copyright © 2011-2022 走看看