Codeforces Round #551 (Div. 2)

Posted hfctf0210

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #551 (Div. 2)相关的知识,希望对你有一定的参考价值。

A:签到,很多人O(n)容易被hack,不如写O(nt)

技术图片
#include<bits/stdc++.h>
using namespace std;
int n,t,ans,mn,s,d;
int main()
{
    scanf("%d%d",&n,&t);
    mn=1e9;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&s,&d);
        while(s<t)s+=d;
        if(s<mn)mn=s,ans=i;
    }
    printf("%d",ans);
}
View Code

B:写起来贼麻烦,对每行/列按照高度排序,然后就是签到题,水平不行写了好长时间才过

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=107;
struct node{int id,tp,h;}c[N*2];
int n,m,h,num,a[N],b[N],has[N][N],mp[N][N],vis1[N],vis2[N];
vector<int>G1,G2;
bool cmp(node a,node b){return a.h>b.h;}
int main()
{
    scanf("%d%d%d",&n,&m,&h);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]),c[++num]=(node){i,0,a[i]};
    for(int i=1;i<=n;i++)scanf("%d",&b[i]),c[++num]=(node){i,1,b[i]};
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    scanf("%d",&has[i][j]);
    sort(c+1,c+num+1,cmp);
    for(int i=100,p=0;i>=1;i--)
    {
        G1.clear(),G2.clear();
        while(p<num&&c[p+1].h==i)
        {
            p++;
            if(!c[p].tp)G1.push_back(c[p].id),vis1[c[p].id]=1;
            else G2.push_back(c[p].id),vis2[c[p].id]=1;
        }
        for(int j=0;j<G1.size();j++)
        for(int k=1;k<=n;k++)
        if(vis2[k]&&has[k][G1[j]])mp[k][G1[j]]=i;
        for(int j=0;j<G2.size();j++)
        for(int k=1;k<=m;k++)
        if(vis1[k]&&has[G2[j]][k])mp[G2[j]][k]=i;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)printf("%d ",mp[i][j]);
        puts("");
    }
}
View Code

C:显然就是把第一位"("和第n位")"去掉,剩下的仍然满足是个括号序列,然后贪心求解

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,now,n1,n2;
char s[N];
int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    if(n&1){puts(":(");return 0;}
    if(s[1]==)||s[n]==(){puts(":(");return 0;}
    if(n==2){puts("()");return 0;}
    s[1]=(,s[n]=);
    for(int i=1;i<=n;i++)if(s[i]==()n1++;else if(s[i]==))n2++;
    if(n1>n/2||n2>n/2){puts(":(");return 0;}
    n1=n/2-n1,n2=n/2-n2;
    for(int i=2;i<n;i++)
    {
        if(s[i]==()now++;
        else if(s[i]==))now--;
        else if(n1)s[i]=(,now++,n1--;
        else s[i]=),now--,n2--;
        if(now<0){puts(":(");return 0;}
    }
    for(int i=1;i<=n;i++)printf("%c",s[i]);
}
View Code

D:很容易想到树形DP,f[i]表示以i为根的子树中,根节点i的最大值,sum[i]表示以i为根的子树中叶节点的个数。然后如果a[i]=1,则f[i]=sum[i]-min{sum[son]-f[son]},反之则f[i]=1+Σ(f[son]-1)

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,m,a[N],f[N],sum[N],fa[N];
vector<int>G[N];
void dfs(int u)
{
    if(!G[u].size()){sum[u]=1,f[u]=1;return;}
    for(int i=0;i<G[u].size();i++)dfs(G[u][i]),sum[u]+=sum[G[u][i]];
    if(a[u])
    {
        int mn=1e9+7;
        for(int i=0;i<G[u].size();i++)mn=min(mn,sum[G[u][i]]-f[G[u][i]]);
        f[u]=sum[u]-mn;
    }
    else{
        int mx=0;
        for(int i=0;i<G[u].size();i++)mx+=f[G[u][i]]-1;
        f[u]=mx+1;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=2;i<=n;i++)scanf("%d",&fa[i]),G[fa[i]].push_back(i);
    dfs(1);
    printf("%d",f[1]);
}
View Code

E:交互题,很容易发现:如果一个框框内答案为奇数,其中必然有且仅有一个头/尾,反之则有0或2个。由于头尾不在一个格子里,可以考虑这样的做法:先询问每一整行,再询问每一整列。发现存在两种情况:1、头尾的行列均不同。2、头尾的行列有一个相同。如果是情况1,则会问出2行和2列答案是奇数,这样再询问4次即可知道答案。如果是情况2,假设在同一行,则问出2列答案是奇数,行答案全是偶数。这时候可以单独询问其中一列,对行进行二分询问。询问次数就是2n+4或者2n+logn

技术图片
#include<bits/stdc++.h>
using namespace std;
int n,nr,nc,R[3],C[3],mp[3][3];
int main()
{
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++)
    {
        printf("? %d 1 %d %d
",i,i,n),fflush(stdout);
        scanf("%d",&x);
        if(x&1)R[++nr]=i;
    }
    for(int i=1,x;i<=n;i++)
    {
        printf("? 1 %d %d %d
",i,n,i),fflush(stdout);
        scanf("%d",&x);
        if(x&1)C[++nc]=i;
    }
    if(nr&&nc)
    {
        for(int i=1;i<=2;i++)
        for(int j=1,x;j<=2;j++)
        {
            printf("? %d %d %d %d
",R[i],C[j],R[i],C[j]),fflush(stdout);
            scanf("%d",&x);
            if(x&1)mp[i][j]=1;
        }
        printf("!");
        for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
        if(mp[i][j])printf(" %d %d",R[i],C[j]);
        return 0;
    }
    if(nr)
    {
        int l=1,r=n,mid,x;
        while(l<r)
        {
            mid=(l+r)/2;
            printf("? %d %d %d %d
",R[1],l,R[1],mid),fflush(stdout);
            scanf("%d",&x);
            if(x&1)r=mid;else l=mid+1;
        }
        printf("! %d %d %d %d",R[1],l,R[2],l);
        return 0;
    }
    if(nc)
    {
        int l=1,r=n,mid,x;
        while(l<r)
        {
            mid=(l+r)/2;
            printf("? %d %d %d %d
",l,C[1],mid,C[1]),fflush(stdout);
            scanf("%d",&x);
            if(x&1)r=mid;else l=mid+1;
        }
        printf("! %d %d %d %d",l,C[1],l,C[2]);
        return 0;
    }
}
View Code

F:留坑,我也不会。

小号rank17 rating+=129 now_rating=2210(和大号最高rating一样,这是巧合还是天注定?!)

以上是关于Codeforces Round #551 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #551 (Div. 2) 题解

Codeforces Round #551 (Div. 2)

Codeforces Round #551 (Div. 2)A. Serval and Bus

CF Round #551 (Div. 2) D

cf-Round551-Div2-D. Serval and Rooted Tree(DP)

Codeforces Round #436 E. Fire(背包dp+输出路径)