Codeforces Round #508 (Div. 2)
题目链接:https://codeforces.com/contest/1038/
A - Equality
题意:给出一个长度为 \(n\) 的大写字母字符串,求最长的子序列,使得这其中的恰好前 \(k\) 种大写字母出现次数相等。
题解:子序列,随便拿。
char s[100005];
int cnt[26];
void test_case() {
    int n, k;
    scanf("%d%d%s", &n, &k, s + 1);
    for(int i = 1; i <= n; ++i)
        ++cnt[s[i] - 'A'];
    int minL = INF;
    for(int i = 0; i < k; ++i)
        minL = min(minL, cnt[i]);
    printf("%d\n", minL * k);
}
B - Non-Coprime Partition
题意:把 \([1,n]\) 的整数分为非空的两组,使得第一组的和与第二组的和不互质。
题解:看起来前后相加就很不互质,总是会是中位数的两倍。所以总是会有中位数作为公因子。
void test_case() {
    int n;
    scanf("%d", &n);
    if(n <= 2) {
        puts("No");
        return;
    }
    puts("Yes");
    printf("%d", (n + 1) / 2);
    for(int i = 1; i <= n; i += 2)
        printf(" %d", i);
    puts("");
    printf("%d", n / 2);
    for(int i = 2; i <= n; i += 2)
        printf(" %d", i);
    puts("");
}
C - Gambling
题意:有两个人,每个人一个长度为 \(n\) 的数字序列,每次操作A先动,可以取走自己的一个数字并获得其得分或者扔掉别人的一个数字。
题解:首先肯定拿自己还是扔别人都是选最大的。那么当别人的比自己大的时候,假如自己拿了别人也拿了,就亏了。自己扔掉别人的那个不会更差。所以可以归纳出贪心。
priority_queue<int> PQA, PQB;
void test_case() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        int x;
        scanf("%d", &x);
        PQA.push(x);
    }
    for(int i = 1; i <= n; ++i) {
        int x;
        scanf("%d", &x);
        PQB.push(x);
    }
    ll sumA = 0, sumB = 0;
    for(int i = 1; i <= n; ++i) {
        if(PQA.empty())
            PQB.pop();
        else {
            if(PQB.empty() || PQA.top() > PQB.top()) {
                sumA += PQA.top();
                PQA.pop();
            } else
                PQB.pop();
        }
        if(PQB.empty())
            PQA.pop();
        else {
            if(PQA.empty() || PQB.top() > PQA.top()) {
                sumB += PQB.top();
                PQB.pop();
            } else
                PQA.pop();
        }
    }
    printf("%lld\n", sumA - sumB);
}
D - Slime
题意:有 \(n\) 个史莱姆,每个史莱姆会有一个分 \(a_i(-10^9\leq a_i \leq 10^9)\) 排成一行,每次会选择一个史莱姆吃掉相邻的一个史莱姆,直到只剩下最后一个,其中 \(x\) 吃掉 \(y\) 之后会剩下 \(x-y\) 。求最大能剩下的史莱姆。
题解:首先要特判只有一个史莱姆的情况,这种不能归纳到下面的规律,直接输出。
然后,假如史莱姆都是正数,那么显然至少有一个的贡献会被变成负数,选最小的变成负数。
假如史莱姆都是负数,那么至少有一个要保持负数,选最大的保持负数。
有0或者有正有负的话,就让负数吃掉几乎所有非负数,只剩下一个非负数,然后让非负数把所有的负数吃完。
void test_case() {
    int n;
    scanf("%d", &n);
    if(n == 1) {
        int x;
        scanf("%d", &x);
        printf("%d\n", x);
        return;
    }
    ll sumP = 0, sumN = 0;
    int minP = INF, maxN = -INF;
    for(int i = 1; i <= n; ++i) {
        int x;
        scanf("%d", &x);
        if(x < 0) {
            sumN += x;
            maxN = max(maxN, x);
        } else {
            sumP += x;
            minP = min(minP, x);
        }
    }
    if(maxN == -INF) {
        printf("%lld\n", sumP - 2 * minP);
        return;
    }
    if(minP == INF) {
        printf("%lld\n", 2 * maxN - sumN);
        return;
    }
    printf("%lld\n", sumP - sumN);
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号