• 雅礼集训2018day1乱写


    图上(dp)大全

    loj6495树

    最终求的是概率,但是显然这个题应该是计数题

    可以得出(2)的根节点必然是(1)

    (f[i][j])表示有(i)个节点,最大深度为(j)的方案数

    四层循环枚举当前点数、当前深度、(2)子树内的点数、(2)子树内的深度

    具体见

    loj6496仙人掌

    仙人掌!考虑先建出圆方树

    定义(f[x][i])表示(x)个点,上面给他的入度为(i),以(x)为根子树内给边定向方案数

    如果(x)是圆点,父亲也是圆点

    (f[x][0])表示它的父亲边指向父亲,(f[x][1])表示父亲边指向自己

    如果(x)是方点

    (f[x][0/1/2])表示环上最靠上的两条边,不指向圆方树上(fa)的边的数量

    如果(x)是圆点,父亲是方点

    (f[x][0/1/2])表示所在环上与自己直接相连的两条边,指向自己的数量

    如果(x)是圆点,那么转移形如

    (f[x][0]=prodlimits_{k_1+k_2+……+k_ple a[x]}f[t][sum_t-k_i])

    观察到是一个背包计数,可以分治(NTT)转移

    如果(x)是方点

    (g[i][0/1])表示处理到环上第(i)个点,其中((i,i+1))是否指向(i+1)

    (g[i+1][0]=g[i][0]*f[t][1]+g[i][1]*f[t][2])

    (g[i+1][1]=g[i][0]*f[t][0]+g[i][1]*f[t][1])

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define lowbit(i) ((i)&(-i))
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=2e5+10,p=998244353,gi=332748118;
    	int n,m,newnode;
    	int a[N];
    	int f[N][3],g[N][2];
    	typedef vector<int> vector;
    	vector t[N];
    	struct graph
    	{
    		int cnt,head[N],nxt[N<<1],to[N<<1];
    		graph(){cnt=1;}
    		inline void link(int x,int y)
    		{
    			nxt[++cnt]=head[x];
    			to[cnt]=y;
    			head[x]=cnt;
    		}
    	}G,P;
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	int dfn[N],low[N],st[N],top,idx;
    	inline void tarjan(int now,int from)
    	{
    		dfn[now]=low[now]=++idx;
    		st[++top]=now;
    		for(int i=P.head[now];i;i=P.nxt[i])
    		{
    			int t=P.to[i];
    			if(!dfn[t])
    			{
    				tarjan(t,i^1);
    				low[now]=min(low[now],low[t]);
    				if(low[t]==dfn[now])
    				{
    					G.link(now,++newnode);
    					do G.link(newnode,st[top]);
    					while (st[top--]!=t);
    				}
    				else if(low[t]>low[now])
    					G.link(now,t),--top;
    			}
    			else if(i!=from) low[now]=min(low[now],dfn[t]);
    		}
    	}
    	int limit,len,_a[N<<2],_b[N<<2],pos[N<<2];
    	inline void ntt(int *a,int inv)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(inv?3:gi,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=(x+y)%p;
    					a[j+k+mid]=(x-y)%p;
    					if(a[j+k+mid]<0) a[j+k+mid]+=p;
    				}
    			}
    		}
    	}
    	inline vector operator * (const vector &a,const vector &b)
    	{
    		if(!a.size()) return b;
    		if(!b.size()) return a;
    		limit=1,len=0;
    		while(limit<=(int)(a.size()+b.size())) limit<<=1,++len;
    		for(int i=0;i<(int)a.size();++i) _a[i]=a[i];
    		for(int i=0;i<(int)b.size();++i) _b[i]=b[i];
        	for(int i=a.size();i<limit;i++) _a[i]=0;
        	for(int i=b.size();i<limit;i++) _b[i]=0;
        	for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
        	ntt(_a,1);ntt(_b,1);
        	for(int i=0;i<limit;++i) _a[i]=_a[i]*_b[i]%p;
        	ntt(_a,0);
        	int inv=fast(limit,p-2);
        	vector c(a.size()+b.size()-1); 
        	for(int i=0;i<(int)c.size();++i) c[i]=_a[i]*inv%p;
        	return c;
    	}
    	vector solve(int l,int r)
    	{
    		if(l==r) return t[l];
    		int mid=(l+r)>>1;
    		vector tl=solve(l,mid),tr=solve(mid+1,r);
    		return tl*tr;
    	}
    	inline void dfs(int now)
    	{
    		for(int i=G.head[now];i;i=G.nxt[i])
    		{
    			int t=G.to[i];
    			dfs(t);
    		}
    		if(now<=n)
    		{
    			if(!G.head[now])
    			{
    				f[now][0]=a[now]>=0,f[now][1]=a[now]>=1,f[now][2]=a[now]>=2;
    				return;
    			}
    			int cnt=0;
    			for(int i=G.head[now];i;i=G.nxt[i])
    			{
    				int v=G.to[i];
    				t[++cnt].clear();
    				if(v>n) t[cnt].push_back(f[v][2]);
    				t[cnt].push_back(f[v][1]),t[cnt].push_back(f[v][0]);
    			}
    			vector tmp=solve(1,cnt);
    			tmp.resize(a[now]+1);
    			for(int i=1;i<(int)tmp.size();++i) tmp[i]=(tmp[i]+tmp[i-1])%p;
    			if(a[now]>=0) f[now][0]=tmp[a[now]];
           		if(a[now]>=1) f[now][1]=tmp[a[now]-1];
            	if(a[now]>=2) f[now][2]=tmp[a[now]-2];
    		}
    		else
    		{
    			vector son;
    			for(int i=G.head[now];i;i=G.nxt[i])
    			{
    				int v=G.to[i];
    				son.push_back(v);
    			}
    			for(int pre=0;pre<2;++pre)
    			{
    				g[0][pre]=1,g[0][pre^1]=0;
    				for(int i=0,v;i<(int)son.size();++i)
    				{
    					v=son[i];
    					g[i+1][0]=(g[i][0]*f[v][1]+g[i][1]*f[v][2])%p;
    					g[i+1][1]=(g[i][0]*f[v][0]+g[i][1]*f[v][1])%p;
    				}
    				if(pre) f[now][2]+=g[son.size()][0]%=p,(f[now][1]+=g[son.size()][1])%=p;
    				else (f[now][1]+=g[son.size()][0])%=p,(f[now][0]+=g[son.size()][1])%=p;
    			}
    		}
    	}
    	inline void main()
    	{
    		n=read(),m=read();
    		for(int x,y,i=1;i<=m;++i)
    		{
    			x=read(),y=read();
    			P.link(x,y);
    			P.link(y,x);
    		}
    		for(int i=1;i<=n;++i) a[i]=read();
    		newnode=n;tarjan(1,0);dfs(1);
    		printf("%lld
    ",f[1][0]);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    

    loj6497图

    考虑在已经处理好的图中新增一点(y),路径数怎么变化

    显然新增加的路径数量要以(y)点结尾

    (f_x)是以(x)为结尾的交错路数量,那么新增加的交错路数量为

    [(sumlimits_{x&col[x] eq col[y]}f_x)+1 ]

    我们最后只关心这个结果的奇偶性

    所以同色点和(f_x)为偶数的点都可以随意连边,对答案无影响,关键在于有多少(f_x)为奇数的点

    我们可以设(dp[i][x][y])表示处理到(y)(x)个黑色的奇数点和(y)个白色的奇数点,(O(n^3)dp)

    更加仔细地观察,我们发现最后答案只和(x+y)的奇偶性有关

    (dp[i][j][x][y])表示前(i)个点,交错路径奇偶性、有没有(f_x)为奇数的黑点,有没有(f_x)为奇数的白点

    考虑转移,如果下一个是白点

    (x=0),那么不管怎么连边,路径数都会加上一个奇数(因为黑点向白点的贡献都是偶数,白点本身又贡献了(1)),奇偶性改变

    (dp[i+1][1-j][x][y]+=2^i*dp[i][j][x][y])

    (x=1),那么路径奇偶性变或不变都是(2^{i-1})种情况,只要考虑要不要把钦定的那个奇数点连上

    (dp[i+1][1-j][x][1]+=2^{i-1}*dp[i][j][x][y])

    (dp[i+1][j][x][y]+=2^{i-1}*dp[i][j][x][y])

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define mid ((l+r)>>1)
    #define lowbit(i) ((i)&(-i))
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=2e5+10,mod=998244353; 
    	int n,opt;
    	int col[N];
    	int f[N][2][2][2],pw[N];
    	inline void add(int &x,int y)
    	{
    		x=x+y;
    		if(x>=mod) x-=mod;
    	}
    	inline void main()
    	{
    		n=read(),opt=read();
    		for(int i=pw[0]=1;i<=n;++i)
    		{
    			col[i]=read();
    			if(col[i]<0) col[i]=3;
    			else ++col[i];
    			pw[i]=pw[i-1]*2%mod;
    		}
    		f[0][0][0][0]=1;
    		for(int i=0;i<n;++i)
    		{
    			for(int j=0;j<2;++j)
    			{
    				for(int x=0;x<2;++x)
    				{
    					for(int y=0;y<2;++y)
    					{
    						if(f[i][j][x][y])
    						{
    							if(col[i+1]&1)//下一个点可以是黑 
    							{
    								if(!y)//没有奇数的白点
    								{
    									add(f[i+1][j^1][1][y],f[i][j][x][y]*pw[i]%mod);
    								}
    								else
    								{
    									add(f[i+1][j][x][y],f[i][j][x][y]*pw[i-1]%mod);
    									add(f[i+1][j^1][1][y],f[i][j][x][y]*pw[i-1]%mod);
    								}
    							}
    							if(col[i+1]&2)
    							{
    								if(!x)
    								{
    									add(f[i+1][j^1][x][1],f[i][j][x][y]*pw[i]%mod);
    								}
    								else
    								{
    									add(f[i+1][j][x][y],f[i][j][x][y]*pw[i-1]%mod);
    									add(f[i+1][j^1][x][1],f[i][j][x][y]*pw[i-1]%mod);
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    		int ans=f[n][opt][0][0]+f[n][opt][1][0]+f[n][opt][0][1]+f[n][opt][1][1];
    		printf("%lld
    ",ans%mod);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    实现一个与内容合二为一的ActionBar动画效果
    hdoj 1506&amp;&amp;1505(City Game) dp
    remine chart2安装
    zoom的学习
    海哥:T2C时代的到来了,那么什么叫T2C?
    minhash算法
    动态创建按钮的JS
    socket编程在windows和linux下的区别
    http staus汇总
    MySQL HINT:Straight_JOIN
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12872867.html
Copyright © 2020-2023  润新知