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

Posted taylorswift13

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于2019/9/17 校内练习赛 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

「csp校内训练 2019-10-30」解题报告

2017.9.17校内noip模拟赛解题报告

团体程序设计天梯赛-练习集 L3-003 社交集群 并查集 解题报告

5.13 校内模拟赛

解题报告

解题报告-2019.12.16