本次练习赛已收录至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])\ i\in[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\n",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\n",u);
if(!Black[u]&&!Black[x[u]])
{
Black[x[u]]=1;
//printf("Black %d\n",x[u]);
++Ans1;
}
--Deg2[x[u]];
if(Deg2[x[u]]==0)
{
q.push(x[u]);
//printf("push %d\n",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\n",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\n",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\n",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\n",x[now[k]],now[k]);
}
}
//int Ha=0;
for(int k=1;k<=Cnt;k++)
{
if(Deg1[now[k]])
{
//++Ha;
//printf("still %d\n",now[k]);
++Ans2;
//puts("++Ans2");
}
}
//printf("Ha=%d Loop=%d\n",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
时间: 2024-11-06 07:18:44