……

解题报告:CF1244D

题目链接;CF1244D Paint the Tree
暴毙。
手玩一下,就会发现只有树是链的情况下才有解,就可以搞到序列上做运算了。
然后莽了一发\(dp\),然后就炸了,原因是一个点的颜色受前两个点控制,而不是只有上一个。
其实确定序列后只有\(3!=6\)中选法,由于第三个是前两个控制的,且是唯一的,然后就行了。
最后把每个点和编号对应起来就好了。
效率是\(\mathcal O(n)\)的,可以通过本题。
下面是我睿智的代码与正解的集合:

\(Code\)

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAXN 100005 
#define INF 1ll<<61
int deg[MAXN];
struct node
{
	int to,nxt;
}e[MAXN<<1];
int head[MAXN],cnt=0;
void add(int l,int r)
{
	e[++cnt].to=r;
	e[cnt].nxt=head[l];
	head[l]=cnt;
}
ll f[5][MAXN],a[5][MAXN],sum,maxn;
int id[MAXN],ans[MAXN];
int c=0;
void dfs(int cur,int fa)
{
	f[0][++c]=a[0][cur];
	f[1][c]=a[1][cur];
	f[2][c]=a[2][cur];
	id[c]=cur;
	for(int i=head[cur];i;i=e[i].nxt) if(fa!=e[i].to) dfs(e[i].to,cur);
}
int n,u,v;
int rt[MAXN],rl;
//我是真的菜 
int main()
{
	#define read(x) scanf("%d",&x)
	#define read_l(x) scanf("%lld",&x)
	read(n);
	for(int i=1;i<=n;i++) read_l(a[0][i]);
	for(int i=1;i<=n;i++) read_l(a[1][i]);
	for(int i=1;i<=n;i++) read_l(a[2][i]);
	for(int i=1;i<n;i++)
	{
		read(u),read(v);
		add(u,v),add(v,u);
		deg[u]++,deg[v]++;
		if(deg[u]>=3||deg[v]>=3)
		{
			printf("%d\n",-1);
			return 0;
		}
	}
	for(int i=1;i<=n;i++) if(deg[i]==1){dfs(i,i);break;}
	/*for(int i=1;i<=n;i++)
	{
		dp[0][i]=dp[1][i]=dp[2][i]=INF;
		for(int j=0;j<=2;j++)
		{
			for(int k=0;k<=2;k++)
			{
				if(j==k) continue;
				if(dp[k][i-1]+f[j][i]<dp[j][i]) dp[j][i]=dp[k][i-1]+f[j][i],t[j][i]=k;
			}
		}
	}*/
	int op=0; 
	maxn=INF;
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			if(i==j) continue;
			op++;
			rt[1]=i,rt[2]=j,sum=f[i-1][1]+f[j-1][2];
			for(int k=3;k<=n;k++) rt[k]=6-rt[k-1]-rt[k-2],sum+=f[rt[k]-1][k];
			if(sum<maxn) maxn=sum,rl=op;
		}	
	} 
	printf("%lld\n",maxn);
	int co=0;
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			if(i==j) continue;
			co++;
			if(co==rl)
			{
				ans[id[1]]=i,ans[id[2]]=j,rt[1]=i,rt[2]=j,sum=f[i-1][1]+f[j-1][2];
				for(int k=3;k<=n;k++) ans[id[k]]=6-rt[k-1]-rt[k-2],rt[k]=ans[id[k]],sum+=f[rt[k]-1][k];
				break;
			}
		}
	}
	/*if(dp[0][n]<dp[1][n]&&dp[0][n]<dp[2][n])
	{
		printf("%lld\n",dp[0][n]);
		ans[id[n]]=1;
		int k=0;
		for(int i=n;i>=2;i--) ans[id[i-1]]=t[k][i]+1,k=t[k][i];
	}
	else if(dp[1][n]<dp[0][n]&&dp[1][n]<dp[2][n])
	{
		printf("%lld\n",dp[1][n]);
		ans[id[n]]=2;
		int k=1;
		for(int i=n;i>=2;i--) ans[id[i-1]]=t[k][i]+1,k=t[k][i];
	}
	else
	{
		printf("%lld\n",dp[2][n]);
		ans[id[n]]=3;
		int k=2;
		for(int i=n;i>=2;i--) ans[id[i-1]]=t[k][i]+1,k=t[k][i];
	}*/
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
} 
posted @ 2020-04-03 22:28  童话镇里的星河  阅读(155)  评论(0编辑  收藏  举报