• 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;
    }
    
  • 相关阅读:
    elastic
    原生js获取css样式和修改css样式
    React项目开发中的数据管理
    js获取鼠标位置
    闭包
    HTML5与HTML4的区别
    JSON 相关
    RESTful Web Services初探
    IE6浏览器兼容问题及部分解决方案
    关于Doctype
  • 原文地址:https://www.cnblogs.com/TaylorSwift13/p/11558809.html
Copyright © 2020-2023  润新知