2019/9/17 校内练习赛 解题报告

比赛详情

本次练习赛已收录至2019/9/22 本周总结

tree

给定一棵无根树,求使得所有节点深度和最大的根节点.

思路

考虑先令(1)为根,(tot)为此时所有节点深度和,预处理(size(x))表示(x)子树的大小.设(u)(1)的某个儿子,显然从(1)走到(u)时,有:

[tot=tot+(n-size[u])-size[u] ]

将结论推广到所有节点,扫描整棵树得到答案,时间复杂度(O(n)).

代码

#include<bits/stdc++.h>
const int SIZE=2000005;

int n,head[SIZE],nex[SIZE],to[SIZE],Tot;
int Dep[SIZE],Siz[SIZE],D[SIZE];
long long Ans;
int Ans_p;

void Link(int u,int v)
{
	nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;
	nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;
}

void DFS(int u,int F)
{
	Siz[u]=1;
	for(int i=head[u];i;i=nex[i])
	{
		int v=to[i];
		if(v==F)continue;
		Dep[v]=Dep[u]+1;
		DFS(v,u);
		Siz[u]+=Siz[v];
		D[u]+=D[v]+Siz[v];
	}
}

void DFS2(int u,int F,long long nowD)
{
	if(Ans<nowD)
	{
		Ans=nowD;
		Ans_p=u;
	}
	if(Ans==nowD)
	{
		Ans_p=std::min(Ans_p,u);
	}
	for(int i=head[u];i;i=nex[i])
	{
		int v=to[i];
		if(v==F)continue;
		DFS2(v,u,nowD+(n-Siz[v])-Siz[v]);
	}
}

int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		Link(u,v);
	}
	Dep[1]=0;
	DFS(1,0);
	DFS2(1,0,D[1]);
	printf("%d",Ans_p);
	return 0;
}

safe

思路

预处理(L[i])([1,i])最大子段和,(R[i])([i+1,n])最大子段和.

答案即为:

[max(L[i]+R[i]) iin[1,n-1] ]

代码

#include<bits/stdc++.h>
const int SIZE=70000;
#define LL long long

int n;
LL x[SIZE],L[SIZE],R[SIZE],DP[SIZE],Ans=-0x3F3F3F3F3F3F3F3F;

int main()
{
	freopen("safe.in","r",stdin);
	freopen("safe.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&x[i]);
	memset(L,-0x3F,sizeof(L));
	memset(R,-0x3F,sizeof(R));
	memset(DP,-0x3F,sizeof(DP));
	for(int i=1;i<=n;i++)
	{
		DP[i]=std::max(DP[i-1]+x[i],x[i]);
		L[i]=std::max(L[i-1],DP[i]);
	}
	memset(DP,-0x3F,sizeof(DP));
	for(int i=n;i;i--)
	{
		DP[i]=std::max(DP[i+1]+x[i],x[i]);
		R[i]=std::max(R[i+1],DP[i]);
	}
	for(int i=2;i<=n;i++)
	{
		Ans=std::max(Ans,L[i-1]+R[i]);
	}
	printf("%lld",Ans);
	return 0;
}

shoot

吐槽

本以为是没有上司的舞会的基环树版,然后假掉了.

本以为是神仙结论题,然后就没有然后了.

最后发现是分情况贪心乱搞,对拍了(n)次终于(似乎)考虑了所有情况.

思路

对每一个连通块分开讨论.

最大值

能自黑就自黑并删掉自黑的点.

剩下的点中,若只剩环,则可以黑掉(环长(-1))个点.

若不是只剩环,入度不为(0)的点,都能被黑.

最小值

拓扑排序处理不在环上的点,该黑就黑,否则不黑.

破环成链,模拟处理环上的点(隔一个黑一个).

代码

#include<bits/stdc++.h>
const int SIZE=2000005;

int n,x[SIZE],Ans1,Ans2;
int head[SIZE],nex[SIZE],to[SIZE],Deg1[SIZE],Deg2[SIZE],Tot,now[SIZE],Cnt;
bool edge[SIZE],Visited[SIZE],Black[SIZE],Loop[SIZE];
int Loop_Tot;

void Link(int u,int v)
{
	nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;edge[Tot]=0;
	nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;edge[Tot]=1;
}

void mk(int u)
{
	if(Visited[u])return;
	//printf("DFS %d
",u);
	Visited[u]=1;
	now[++Cnt]=u;
	for(int i=head[u];i;i=nex[i])
	{
		int v=to[i];
		mk(v);
	}
}

std::queue<int>q;
void Topo(int o)
{
	//puts("*********************");
	while(q.size())
	{
		int u=q.front();
		q.pop();
		//printf("pop %d
",u);
		if(!Black[u]&&!Black[x[u]])
		{
			Black[x[u]]=1;
			//printf("Black %d
",x[u]);
			++Ans1;
		}
		--Deg2[x[u]];
		if(Deg2[x[u]]==0)
		{
			q.push(x[u]);
			//printf("push %d
",x[u]);
		}
			
	}
	//puts("*********************");
	int Flag=0;
	bool Finished=0;
	for(int i=1;i<=Cnt;i++)
	{
		if(Deg2[now[i]])
		{
			Loop[now[i]]=1;
			o=now[i];
			//printf("Loop %d
",now[i]);
			++Loop_Tot;
		}
	}
	
	for(int i=o;i;i=x[i])
	{
		if(i==o)
		{
			if(Finished==0)Finished=1;
			else break;
		}
		if(Black[i]==1)
		{
			Flag=i;
			break;
		}
	}
	bool now=1;
	if(Flag==0)
	{
		Flag=o;
		now=0;
	}
	/*else
	{*/
		
		Finished=0;
		Flag=x[Flag];
		for(int i=Flag;i;i=x[i])
		{
			if(i==Flag)
			{
				if(Finished==0)Finished=1;
				else break;
			}
			if(Black[i]==1)
			{
				now=1;
				continue;
			}
			else
			{
				now^=1;
				if(now)
				{
					Black[i]=1;
					//printf("Black %d
",i);
					++Ans1;
				}
			}
		}			
	//} 
}
bool PD[SIZE];

int main()
{
	freopen("shoot.in","r",stdin);
	freopen("shoot.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x[i]);
		Deg1[x[i]]++;
		Deg2[x[i]]++;
		Link(i,x[i]);
	}
	for(int i=1;i<=n;i++)
	{
		/*if(x[i]==i)//×Ô»· 
		{
			++Ans1;
			++Ans2;
			continue;
		}*/
		if(!Visited[i])
		{
			//puts("");
			Cnt=0;
			Loop_Tot=0;
			mk(i);
			int Ha=Cnt;
			if(Cnt==1)
			{
				++Ans1;
				++Ans2;
				continue;
			}
			else
			{
				for(int k=1;k<=Cnt;k++)
				{
					//printf("%d ",now[k]);
					//puts("");
					if(Deg1[now[k]]==0)
					{
						++Ans2;
						//puts("++Ans2");
						q.push(now[k]);
						//printf("push %d
",now[k]);
						PD[now[k]]=1;
						--Ha;
					}
				}
				Topo(i);
				for(int k=1;k<=Cnt;k++)
				{
					if(PD[now[k]]==1)
					{
						--Deg1[x[now[k]]];
						//printf("--Deg %d owing to %d
",x[now[k]],now[k]);
					}
				}
				//int Ha=0;
				for(int k=1;k<=Cnt;k++)
				{
					if(Deg1[now[k]])
					{
						//++Ha;
						//printf("still %d
",now[k]);
						++Ans2;
						//puts("++Ans2");
					}
				}
				//printf("Ha=%d Loop=%d
",Ha,Loop_Tot);
				if(Ha==Loop_Tot&&Ha!=1)
				{
					--Ans2;
					//puts("--Ans2");
				}				
			}
		}
	}
	printf("%d %d",Ans1,Ans2);
	return 0;
}

附:暴力代码

#include<bits/stdc++.h>
const int SIZE=1000005;

int n,x[SIZE],P[SIZE],Deg[SIZE],Ans1=10,Ans2;
bool Visited[SIZE],mk[10];

void DFS2(int step,int Ans)
{
	if(step==n+1)
	{
		Ans1=std::min(Ans1,Ans);
		Ans2=std::max(Ans2,Ans);
		return;
	}
	int i=P[step];
	if(mk[i])DFS2(step+1,Ans);
	else
	{
		if(Deg[i]==0)
		{
			//自黑 
			if(mk[i]==0)
			{
				mk[i]=1;
				DFS2(step+1,Ans+1);
				mk[i]=0;
			}
			
			if(mk[i]==1)
			{
				DFS2(step+1,Ans);
			}
			//黑别人 
			if(mk[x[i]]==0)
			{
				mk[x[i]]=1;
				DFS2(step+1,Ans+1);
				mk[x[i]]=0;
			}
			
			if(mk[x[i]]==1)
			{
				DFS2(step+1,Ans);
			}
		}
		else
		{
			if(mk[x[i]]==0)
			{
				mk[x[i]]=1;
				DFS2(step+1,Ans+1);
				mk[x[i]]=0;
			}
			
			if(mk[x[i]]==1)
			{
				DFS2(step+1,Ans);
			}				
		}		
	}

}

void DFS(int step)
{
	if(step==n+1)
	{
		/*for(int i=1;i<=8;i++)
			printf("%d",P[i]);
		puts("");*/
		memset(mk,0,sizeof(mk));
		DFS2(1,0);
	}
	for(int i=1;i<=n;i++)
	{
		if(!Visited[i])
		{
			Visited[i]=1;
			P[step]=i;
			DFS(step+1);
			Visited[i]=0;
		}
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x[i]);
		Deg[x[i]]++;
	}
	DFS(1);
	printf("%d %d",Ans1,Ans2);
	return 0;
}
原文地址:https://www.cnblogs.com/TaylorSwift13/p/11558809.html