Codeforces Round #646 (Div. 2) / contest 1363


A B C D E F

( √:做出; ●:尝试未做出; ○:已补题 )


题目地址:https://codeforces.com/contest/1363

这一次比赛真是“命途多舛”,A题WA了两发,到半个多小时才写出来,E题WA了四发,C也因为智障错误WA了一次,特别是E卡了好久,结果最后看D的时候已经有了思路,可惜不够时间了。



A Odd Selection

题意:问能不能从一堆数字中找出 x 个并且和为奇数。

思路:统计奇数个数和偶数个数,如果 x 小于等于偶数个数,那么是否存在方案就在于是否存在奇数;否则,选取最多的偶数,是的剩余的 x 为奇数,然后看剩余的 x 是否不大于奇数个数。

本来是很简单的,可以比赛的时候一个地方搞错了,然后就……

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    //freopen("input.txt","r",stdin);
    int T=read();
    while(T--)
    {
        int n=read(),x=read(),ji=0,ou=0;
        REP(i,1,n)
        {
            if(read()&1) ji++;
            else ou++;
        }
        if(x<=ou) puts(ji>0?"Yes":"No");
        else
        {
            if((x-ou)&1) x-=ou;
            else if(ou>0) x-=ou-1;
            puts((x&1) && x<=ji?"Yes":"No");
        }
    }

    return 0;
}



B Subsequence Hate

题意

思路

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=1005;
int f[maxn][2],n;
char s[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    int t=read();
    while(t--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        REP(i,0,n+4) f[i][0]=f[i][1]=0;
        REP(i,1,n)
        {
            f[i][0]=f[i-1][0];
            f[i][1]=f[i-1][1];
            if(s[i]=='0') f[i][0]++;
            else f[i][1]++;
        }
        int ans=1e9;
        REP(i,1,n+1)
        {
            ans=min(ans,f[i-1][1]+f[n][0]-f[i-1][0]);
            ans=min(ans,f[i-1][0]+f[n][1]-f[i-1][1]);
        }
        printf("%d\n",ans);
    }

    return 0;
}



C Game On Leaves

题意:一颗树,有一个结点为特殊结点,两个人玩游戏,每个人每次只能拿走一个叶子结点和相连的那一条边,谁拿到特殊结点谁就赢,问谁赢。

思路:记录每个结点的度,如果特殊结点的度小于等于1,那么先手必胜(比赛一开始忘记考虑一个结点,也就是度为0的情况了),否则可以证明(以及猜到),当结点个数为奇数时后手必胜,反之先手必胜。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=1005;
int du[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    int t=read();
    while(t--)
    {
        int n=read(),x=read();
        REP(i,1,n) du[i]=0;
        REP(i,1,n-1)
        {
            int u=read(),v=read();
            du[u]++; du[v]++;
        }
        if(du[x]==1 || n==1) {puts("Ayush"); continue;}
        puts(n&1?"Ashish":"Ayush");
    }

    return 0;
}



D Guess The Maximums

题意:一道交互题。有一个长为 n( n 1000 n\le 1000 ) 的数组 A,以及 k 个互不相交的集合 S[],定义 p [ i ] = max j S i A [ j ] p[i]=\max\limits_{j\notin S_i}A[j] 。你可以最多询问 12 次,每次给出一个数集 S,评测机会返回 max i S A [ i ] \max\limits_{i\in S}A[i] 。要求求出数组 p 。

思路:比赛的时候通过数据 (1000,12)已经猜到这是一个二分,而且也有了一些思路,可惜E题浪费太多时间没时间想了。其实 p[i] 就是所有下标不在 S[i] 中的 A 中最大的值,我们设 m 为 A 中最大的值,那么最多只有可能只有一个 p[q] 不等于 m,这种情况对应于 S[q] 包含了唯一的最大值的下标。那么我们的目标就是找到这个 q,然后单独处理。找 q 的次数为 logn 次最多为 10,加上求 A 最大值和最后单独处理,正好最多12次询问。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=1005;
int n,k,t,vis[maxn],m,ans[maxn];
vector<int> a[maxn];
char s[maxn];

int getR(int l,int r)
{
    int sum=0;
    REP(i,l,r) sum+=a[i].size();
    printf("? %d ",sum);
    REP(i,l,r) REP(j,0,a[i].size()-1) printf("%d ",a[i][j]);
    puts(""); fflush(stdout);
    return read();
}

int main()
{
    //freopen("input.txt","r",stdin);
    t=read();
    while(t--)
    {
        n=read(),k=read();
        REP(i,1,k) a[i].clear();
        REP(i,1,k)
        {
            int c=read();
            while(c--) a[i].push_back(read());
        }
        printf("? %d ",n);
        REP(i,1,n) printf("%d ",i); puts("");
        fflush(stdout);
        m=read();
        REP(i,1,k) ans[i]=m;

        int l=1,r=k,mid,m1,m2;
        while(l<r)
        {
            mid=(l+r)>>1;
            m1=getR(l,mid);
            if(m1==m) r=mid;
            else l=mid+1;
        }
        if(l<=r)
        {
            printf("? %d ",n-a[l].size());
            REP(i,1,n)
            {
                int flag=0;
                REP(j,0,a[l].size()-1) if(a[l][j]==i) flag=1;
                if(!flag) printf("%d ",i);
            }
            puts("");
            fflush(stdout);
            ans[l]=read();
        }
        printf("! ");
        REP(i,1,k) printf("%d ",ans[i]);
        puts("");
        fflush(stdout);
        scanf("%s",s);
        if(strcmp(s,"Correct")) break;
    }

    return 0;
}



E Tree Shuffling

题意:有一颗根结点为 1 的树,每个结点有个权值 a[i],一个当前状态 b[i] (0/1),以及一个目标状态 c[i] (0/1) 。每次操作可以选择一个结点 u,然后从 u 的子树中选取 k 个结点,把他们的状态打乱随意分配,这一次操作代价为 a[i]*k,问最少的代价,使得所有结点的状态变为目标状态。

思路:对于一个结点管辖的子树,如果它父结点路径上存在一个结点的 a 比它小,那么它的子树的 shuffle 由那个更小的结点来处理更优。所以做法就是:对每个结点 dfs 的时候统计它的子树需要变为0 和需要变为1 的个数,然后如果这个结点的 a 不大于其父结点路径上的所有结点,就及时 shuffle 并累计代价。

比赛的时候一开始想错了,一开始的做法只考虑了两侧之间的处理,而没有想到最小代价要跟整个父结点路径扯上关系,后来是自己写了个数据测才发现的。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
typedef long long LL;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=2e5+5;
vector<int> G[maxn];
int n,a[maxn],b[maxn],c[maxn],h[maxn][2];
LL ans;

void dfs(int u,int fa,int minx)
{
    minx=min(minx,a[u]);
    REP(i,0,G[u].size()-1) if(G[u][i]!=fa) dfs(G[u][i],u,minx);
    REP(i,0,G[u].size()-1)
    {
        int v=G[u][i];
        if(v==fa) continue;
        h[u][0]+=h[v][0]; h[u][1]+=h[v][1];
    }
    if(b[u]!=c[u]) h[u][c[u]]++;
    if(a[u]<=minx)
    {
        int x=min(h[u][0],h[u][1]);
        ans+=1ll*x*2*a[u];
        h[u][0]-=x; h[u][1]-=x;
    }
}

int main()
{
    //freopen("input.txt","r",stdin);
    n=read();
    REP(i,1,n) a[i]=read(),b[i]=read(),c[i]=read();
    REP(i,1,n-1)
    {
        int u=read(),v=read();
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0,1e9+5);
    if(h[1][0]!=h[1][1]) puts("-1");
    else printf("%lld\n",ans);

    return 0;
}



F

题意

思路

代码


猜你喜欢

转载自blog.csdn.net/dragonylee/article/details/106482684
今日推荐