zoukankan      html  css  js  c++  java
  • CF379G New Year Cactus 题解

    P.S.

    从下午 2:00 做到晚上 9:30!!!

    Codeforces
    Luogu

    Description.

    看到仙人掌就想到圆方树。
    考虑这题能否把一个环的贡献拆到方点上去,这样就可以做了。

    考虑定义一个方点的颜色是它对应环的两端颜色,如果一黑一白就让它为灰色。
    那这样每个点所对应的颜色是可以直接求的。
    如果它是圆点,那直接树形 dp,用树形背包方法合并。
    如果它是方点,那枚举它最左边的儿子是什么颜色,然后断环为链,用序列 dp 的方法转移。

    然后嘴巴就嘴巴完了,不过这题 起来很容易写起来挺屎的。
    或者可能我写地比较屎,反正给爷整吐了。

    Coding.

    点击查看代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    template<int N,int M>struct Edge
    {
    	struct edge{int to,nxt;}e[M<<1];int et,head[N];
    	inline void Adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
    	inline void adde(int x,int y) {Adde(x,y),Adde(y,x);}
    	inline void clear() {et=0,memset(head,0,sizeof(head));}
    #define Go(A,x,v) for(int Ed=A.head[x],v=A.e[Ed].to;Ed;v=A.e[Ed=A.e[Ed].nxt].to)
    };Edge<2505,5005>E;Edge<5005,5005>Tr;
    const int N=3755;int n,m,tt,f[N],dfn[N],low[N],dt,dp[N][N][4],sz[N];
    inline void tarjan(int x,int fa)
    {
    	f[x]=fa,dfn[x]=low[x]=++dt;
    	Go(E,x,y)
    	{
    		if(!dfn[y]) tarjan(y,x),low[x]=min(low[x],low[y]);
    		else if(y!=fa) low[x]=min(low[x],dfn[y]);
    		if(low[y]>dfn[x]) Tr.adde(x,y);
    	}
    	Go(E,x,y) if(f[y]!=x&&dfn[y]>dfn[x])
    	{
    		tt++,Tr.adde(tt,x);
    		for(int u=y;u^x;u=f[u]) Tr.adde(tt,u);
    	}
    }
    inline void chkmx(int &a,int b) {a=max(a,b);}
    int debug[N][4],tmp[N][4];
    inline void solve(int x,int fa)
    {//dp k 个 1 点最多有几个 2 点
    	Go(Tr,x,y) if(y!=fa) solve(y,x);
    	if(x<=n)
    	{
    		sz[x]=1,memset(dp[x],~0x3f,sizeof(dp[x])),memset(dp[x][0],0,sizeof(dp[x][0]));
    		Go(Tr,x,y) if(y!=fa)
    		{
    			int od=sz[x];sz[x]+=sz[y];
    			for(int i=0;i<=od;i++) memcpy(debug[i],dp[x][i],sizeof(debug[i]));
    			for(int i=od;i>=0;i--) for(int a=3;~a;a--)
    				for(int j=sz[y];j>=0;j--) for(int b=3;~b;b--)
    					chkmx(dp[x][i+j][a|b],debug[i][a]+dp[y][j][b]);
    //printf("f**k %d : ",x);for(int i=0;i<=sz[x];i++) printf("<%d,%d,%d,%d>%c",dp[x][i][0],dp[x][i][1],dp[x][i][2],dp[x][i][3],i==sz[x]?'\n':' ');
    		}
    		for(int i=0;i<=sz[x];i++) memcpy(debug[i],dp[x][i],sizeof(debug[i])),memset(dp[x][i],~0x3f,sizeof(dp[x][i]));
    		for(int i=0;i<=sz[x];i++)
    		{
    			for(int a=0;a<4;a++) if(i+(a==1)<=sz[x]) chkmx(dp[x][i+(a==1)][a],debug[i][0]+(a==2));
    			chkmx(dp[x][i][0],debug[i][1]);if(i^sz[x]) chkmx(dp[x][i+1][1],debug[i][1]);
    			chkmx(dp[x][i][0],debug[i][2]);chkmx(dp[x][i][2],debug[i][2]+1);
    			chkmx(dp[x][i][0],debug[i][3]);
    		}
    	}else
    	{
    		Go(Tr,x,y) if(y!=fa) sz[x]+=sz[y];
    		memset(dp[x],~0x3f,sizeof(dp[x]));
    		for(int bit=0;bit<3;bit++)
    		{
    			char fg=0;int Sz=1;memset(tmp,~0x3f,sizeof(tmp));
    			Go(Tr,x,y) if(y!=fa)
    			{
    				if(!fg)
    				{
    					for(int i=0;i<=sz[y];i++) tmp[i][bit]=dp[y][i][bit];
    					Sz+=sz[y],fg=1;continue;
    				}
    				else
    				{
    					for(int i=0;i<=Sz;i++) memcpy(debug[i],tmp[i],sizeof(debug[i]));
    					for(int i=Sz;i>=0;i--) for(int j=sz[y];j>=0;j--)
    					{
    						for(int a=0;a<3;a++) chkmx(tmp[i+j][0],debug[i][a]+dp[y][j][0]);
    						chkmx(tmp[i+j][1],max(debug[i][0],debug[i][1])+dp[y][j][1]);
    						chkmx(tmp[i+j][2],max(debug[i][0],debug[i][2])+dp[y][j][2]);
    					}
    					Sz+=sz[y];
    				}
    			}
    //printf("f**k %d : ",x);for(int i=0;i<=sz[x];i++) printf("<%d,%d,%d,%d>%c",tmp[i][0],tmp[i][1],tmp[i][2],tmp[i][3],i==sz[x]?'\n':' ');
    			for(int i=0;i<=sz[x];i++)
    			{
    				chkmx(dp[x][i][bit],tmp[i][0]);
    				chkmx(dp[x][i][bit|1],tmp[i][1]);
    				chkmx(dp[x][i][bit|2],tmp[i][2]);
    			}
    		}
    	}
    //printf("res %d : ",x);for(int i=0;i<=sz[x];i++) printf("<%d,%d,%d,%d>%c",dp[x][i][0],dp[x][i][1],dp[x][i][2],dp[x][i][3],i==sz[x]?'\n':' ');
    }
    int main()
    {
    	read(n,m);for(int i=1,x,y;i<=m;i++) read(x,y),E.adde(x,y);
    	tt=n,tarjan(1,0),solve(1,0);
    	for(int i=0;i<=n;i++) printf("%d%c",max(max(dp[1][i][0],dp[1][i][1]),max(dp[1][i][2],dp[1][i][3])),i==n?'\n':' ');
    	return 0;
    }
    
  • 相关阅读:
    九度OJ 1031:xxx定律 (基础题)
    九度OJ 1030:毕业bg (01背包、DP)
    九度OJ 1029:魔咒词典 (排序)
    九度OJ 1028:继续畅通工程 (最小生成树)
    九度OJ 1027:欧拉回路 (欧拉回路)
    九度OJ 1026:又一版 A+B (进制转换)
    九度OJ 1025:最大报销额 (01背包、DP)
    九度OJ 1024:畅通工程 (最小生成树)
    九度OJ 1023:EXCEL排序 (排序)
    九度OJ 1022:游船出租 (统计)
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15404383.html
Copyright © 2011-2022 走看看