• 联考20200522 T3 「雅礼集训 2018 Day1」仙人掌


    题目传送门

    分析:
    首先考虑树的情况吧
    (f[u][i])表示(u)经过与一些儿子连了边之后剩余(i)的度数
    列出式子:

    (f[u][i]=f[u][i]*sum[son][1]+f[u][i+1]*sum[son][0])

    这里的(sum)是后缀和
    (D)为度数,复杂度为(O(sum D^2))
    菊花图直接T到飞起
    观察DP式子,发现实际为(D)个2阶多项式全部乘起来,可以使用分治NTT,复杂度变成(O(sum Dlog^{2}D))

    然后考虑仙人掌的情况。。。
    大佬云:“如何胃疼到没事找事,只需要找一个树上问题,情况改为仙人掌并做出来”
    (着实在理
    先建出圆方树(注意桥不作为一个单独的方点),但是圆点的dp式子会改变
    当儿子为圆点时:

    (f[u][i]=f[u][i]*sum[son][1]+f[u][i+1]*sum[son][0])

    当儿子为方点时:

    (f[u][i]=f[u][i]*sun[son][2]+f[u][i+1]*sum[son][1]+f[u][i+2]*sum[son][0])

    方点的情况相当于父亲连着环上的两条边,于是两条边度数变化从{0,1}变成了{0,1,2}
    实际还是(D)个低阶多项式乘起来,分治NTT解决

    考虑方点的转移。。

    我们取一条原来环上一条连接方点儿子和父亲的边,强行确定它的方向
    然后按顺序进行dp
    (实际上这个dp就是乘法,满足交换律,不需要沿着环边顺序)
    (g[0/1][u][0/1])表示确定第一条边朝向(0/1)(u)是否被上一个点指向,(u)为表示环的方点
    初始时(g[0][u][0]=1,g[1][u][1]=1)

    (g[u][0]=g[u][0]*f[son][1]+g[u][1]*f[son][2])
    (g[u][1]=g[u][0]*f[son][0]+g[u][1]*f[son][1])
    (f[fa][2]=g[1][u][0],f[fa][1]=g[1][u][1]+g[0][u][0],f[fa][0]=g[0][u][1])

    暴力转移,复杂度是线性的

    然后OJ很卡,疯狂卡常。。。。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<iostream>
    #include<map>
    #include<string>
    
    #define maxn 200005
    #define MOD 998244353
    #define Poly vector<int>
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m,tot;
    int f[maxn][3],vis[maxn],a[maxn];
    vector<int>V[maxn],id[maxn];
    Poly p[maxn];
    int d[maxn];
    int fir[maxn],nxt[maxn],to[maxn],cnt;
    int Wl,Wl2,w[maxn<<2];
    int rev[maxn<<2];
    int dfn[maxn],low[maxn],tim,stk[maxn],tp;
    
    int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    void init(int N)
    {
    	Wl=w[0]=1;
    	while((Wl<<1)<=N)Wl<<=1;
    	w[1]=ksm(3,(MOD-1)/(Wl<<1)),Wl2=Wl<<1;
    	for(int i=2;i<=Wl2;i++)w[i]=1ll*w[i-1]*w[1]%MOD;
    }
    
    int upd(int x){return x<MOD?x:x-MOD;}
    void newnode(int u,int v)
    {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
    void tarjan(int u)
    {
    	dfn[u]=low[u]=++tim;stk[++tp]=u;
    	for(int i=0;i<V[u].size();i++)if(!vis[id[u][i]])
    	{
    		int v=V[u][i];vis[id[u][i]]=1;
    		if(!dfn[v])
    		{
    			tarjan(v),low[u]=min(low[u],low[v]);
    			if(low[v]==dfn[u])
    			{
    				newnode(u,++tot);int x;
    				do{x=stk[tp--],newnode(tot,x);}while(x!=v);
    			}
    			else if(low[v]>dfn[u])newnode(u,v),tp--;
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    
    void NTT(Poly &a,int opt,int N)
    {
    	for(int i=0;i<N;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1,B=Wl;i<N;i<<=1,B>>=1)
    		for(int j=0,t=i<<1;j<N;j+=t)for(int k=0,x=0;k<i;k++,x+=B)
    		{
    			int v=1ll*a[i+j+k]*w[opt==1?x:Wl2-x]%MOD;
    			a[i+j+k]=upd(a[j+k]-v+MOD),a[j+k]=upd(a[j+k]+v);
    		}
    	if(!~opt)for(int i=0,Inv=ksm(N,MOD-2);i<N;i++)a[i]=1ll*a[i]*Inv%MOD;
    }
    
    Poly mul(Poly A,Poly B)
    {
    	int len=A.size()+B.size()-1,N=1;
    	while(N<len)N<<=1;A.resize(N),B.resize(N);
    	for(int i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|(i&1?N>>1:0);
    	NTT(A,1,N),NTT(B,1,N);
    	for(int i=0;i<N;i++)A[i]=1ll*A[i]*B[i]%MOD;
    	NTT(A,-1,N);A.resize(len);
    	return A;
    }
    
    Poly solve(int l,int r)
    {
    	if(l==r)return p[l];
    	int mid=(l+r)>>1;
    	return mul(solve(l,mid),solve(mid+1,r));
    }
    
    void dfs(int u)
    {
    	for(int i=fir[u];i;i=nxt[i])dfs(to[i]);
    	if(u<=n)
    	{
    		if(!fir[u]){f[u][0]=1,f[u][1]=(a[u]>=1),f[u][2]=(a[u]>=2);return;}
    		cnt=0;
    		for(int i=fir[u];i;i=nxt[i])
    		{
    			p[++cnt].clear();
    			if(to[i]>n)p[cnt].push_back(f[to[i]][2]);
    			p[cnt].push_back(f[to[i]][1]),p[cnt].push_back(f[to[i]][0]);
    		}
    		Poly A=solve(1,cnt);A.resize(a[u]+1);
    		for(int i=1;i<=a[u];i++)A[i]=upd(A[i]+A[i-1]);
    		f[u][0]=A[a[u]];
    		if(a[u]>=1)f[u][1]=A[a[u]-1];
    		if(a[u]>=2)f[u][2]=A[a[u]-2];
    	}
    	else
    	{
    		for(int k=0;k<=1;k++)
    		{
    			int g0=!k,g1=k;
    			for(int i=fir[u];i;i=nxt[i])
    			{
    				int tmp0=upd((1ll*g0*f[to[i]][1]+1ll*g1*f[to[i]][2])%MOD);
    				int tmp1=upd((1ll*g0*f[to[i]][0]+1ll*g1*f[to[i]][1])%MOD);
    				g0=tmp0,g1=tmp1;
    			}
    			f[u][k+1]=upd(f[u][k+1]+g0),f[u][k]=upd(f[u][k]+g1);
    		}
    	}
    }
    
    int main()
    {
    	n=getint(),m=getint();
    	init(2*n);
    	for(int i=1;i<=m;i++)
    	{
    		int u=getint(),v=getint();
    		V[u].push_back(v),V[v].push_back(u);d[u]++,d[v]++;
    		id[u].push_back(i),id[v].push_back(i);
    	}
    	for(int i=1;i<=n;i++)a[i]=min(getint(),d[i]);
    	tot=n,tarjan(1),dfs(1);
    	printf("%d
    ",f[1][0]);
    }
    

  • 相关阅读:
    Merge Intervals
    Insert Interval
    Combination Sum
    Trapping Rain Water II
    Kth Largest in N Arrays
    Spiral Matrix
    Search a 2D Matrix
    Binary Postorder Traversal
    Search in Rotated Sorted Array II
    S3C2440移植uboot之启动过程概述
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12939942.html
Copyright © 2020-2023  润新知