Codeforces Round #829 (Div. 2)

Posted on 2022-10-24 18:04  Capterlliar  阅读(41)  评论(1编辑  收藏  举报

B. Kevin and Permutation

题意:构造一个n的排列,使得 min |a[i+1]-a[i]| 最大。

解:数字都是两两比较,所以最大值不会超过n/2。考虑1, 1+n/2, 2, 2+n/2...这个序列中1+n/2-2=n/2-1,不好。所以改成1+n/2, 1, 2+n/2, 2...

C1. Make Nonzero Sum (easy version)

题意:规定在数列上一种计算s=a1-a2+a3-a4+...现给出一个数列,要求将其分为若干组,使得每组运算结果之和为0.

解:首先有奇数个数肯定分不出。一开始想的把偶数位的数正负号变一下,加到为0为一组,然后发现是要每组算一个数,再加起来等于0。也就是可以正负抵消。介于值只有1和-1两种,所以把它们按顺序两两配对。相同的分在一组,凑出一个0;不同的分两组,加起来也是0.

C2. Make Nonzero Sum (hard version)

题意:在上一题的基础上给数组加入0。要求不变。

解:0很好呀,可以看作没有。0造成的影响是比如原来[1, 1]分成一组,现在[1, 0, 1]就不能分成一组了,但[1, 0, 0, 1]还是可以分成一组。对于相邻的两个1和-1不影响。那么考虑[1, 0, 1]怎么处理,看一眼样例,很好样例已经把答案写上了。分一个0给后面的1,让它变成-1。最后进行一个大的分类讨论。

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 200005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 998244353
int a[maxx]={0};
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int sum=0;
        for(int i=1;i<=n;i++){
            sum+=a[i];
        }
        if(sum%2){
            printf("-1\n");
            continue;
        }
        vector<pair<int,int> > ans;
        int pre=0,pos=1;
        while(pos<=n){
            if(a[pos]!=0){
                if(pre==0){
                    pre=pos;
                }
                else{
                    if(a[pos]==a[pre]&&(pos-pre-1)%2){
                        ans.push_back(make_pair(pre,pre));
                        ans.push_back(make_pair(pre+1,pos));
                    }
                    if(a[pos]==a[pre]&&(pos-pre-1)%2==0){
                        ans.push_back(make_pair(pre,pos));
                    }
                    if(a[pos]!=a[pre]){
                        ans.push_back(make_pair(pre,pre));
                        ans.push_back(make_pair(pos,pos));
                    }
                    pre=0;
                }
            }
            pos++;
        }
        vector<pair<int,int> > ans2;
        int end=0;
        for(auto [l,r]:ans){
            if(l-end>1){
                ans2.push_back(make_pair(end+1,l-1));
            }
            ans2.push_back(make_pair(l,r));
            end=r;
        }
        if(n-end>0)
            ans2.push_back(make_pair(end+1,n));
        printf("%d\n",ans2.size());
        for(auto [l,r]:ans2){
            printf("%d %d\n",l,r);
        }
    }
    return 0;
}
View Code

D. Factorial Divisibility

题意:给出x和n个数,设这n个数为a1, a2, a3...an,问 a1!+a2!+a3!+...an! 是否能被 x! 整除。

解:试图对 a1!+a2!+a3!+...an! 这个式子进行一些处理,因为要除以 x! ,所以先提取出2,设num[i]为数字 i 的个数,式子变成 num[1]/2+num[2]+3*(num[3]+4*(...))),num[1]/2必须是整数;同理,接着提取出3,式子变成 (num[1]/2+num[2])/3+num[3]+4*(...)),(num[1]/2+num[2])/3必须是整数,剩下的同理,一直提取到x-1,看看每次是否都能除尽。如果有一个不能,就无法整除;反正可以整除。x-1之后不用检查,x!肯定能整除x!。

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 500005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 998244353
int num[maxx]={0};
signed main() {
//    int T;
//    scanf("%d",&T);
//    while(T--){
//
//    }
    int n,x;
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++){
        int t;
        scanf("%d",&t);
        num[t]++;
    }
    int ans=num[1];
    for(int i=1;i<x;i++){
        if(ans%(i+1)==0){
            ans=ans/(i+1)+num[i+1];
        }
        else{
            printf("No\n");
            return 0;
        }
    }
    printf("Yes\n");
    return 0;
}
//(num[1]+2*(num[2]+3*(num[3]+4*(...))))/2..x
////num[1]/2+num[2]+3*(num[3]+4*(...))))/3...x
////(num[1]/2+num[2])/3+num[3]+4*(...)))/4...x
View Code

E. Wish I Knew How to Sort

Wish I Knew How to AC

题意:给出一个01序列,每次随机挑俩数a[l]和a[r](l<r),如果 a[l]<a[r] 就交换它们的位置。操作若干次(即使不交换也算作一次操作),如果要使最终结果有序,求执行几次操作的期望。

解:期望题,看到n的范围为2e5,先设个dp[i]。先算了下样例,想设dp[i]为有i个逆序对时的期望,然后进行了一堆无效观察,决定去看一点题解。假设有g个0,设dp[i]为前g个数中有i个0时的期望,显然dp[g]=0。或者换一种说法是换i次能使其有序,这个状态好转移多了。下一次选中的两个数要命能交换,要么不能,设p为能交换的概率。dp[i]=p*dp[i+1]+(1-p)*dp[i]+1,最后那个1是因为本次也是选了一次的。