Codeforces Round #717 (Div. 2)ABCD题解


A - Tit for Tat

题意:给你长为 n n n的数组, 你可以进行 k k k次操作。任意挑选两个元素进行一个加 1 1 1 一个减 1 1 1 操作,使数组变成字典序最小的不包含负数的数组

所以就是从前往后进行k次操作能减就减为0,不能减为0的话就减剩下来的 k k k,加一的话就在最后一个的元素加 k k k,保证字典序最小。

#include <iostream>
#define ll long long
using namespace std;
const int N = 1e6 + 9;
 ll n, m, t, k, x, q, l, r, a[N], b[N], cnt, maxx;
 multiset<ll> se;
int main(){
    cin>>t;
    while(t--) {
        cin>>n>>k;
        for(int i=1; i<=n; i++) {
            cin>>a[i];
        }
        for(int i=1; i<n; i++) {
            if(a[i]==0) continue;
            if(!k) break;
            if(a[i]<=k) {
            	a[n]+=a[i];
            	k-=a[i];
                a[i]=0;//赋值为0的放在最后,比赛的时候差点直接交了
            }else {
                a[i]-=k;
                a[n]+=k;
                k=0;//一样
            }
        }
        for(int i=1; i<=n; i++) {
            cout<<a[i]<<" \n"[i==n];
        }
    }
    return 0;
}

B - AGAGA XOOORRR

题意:给你个数组,判断能不能对两个相邻的元素进行异或,然后把异或结果放在这两数的位置,数组长度减一,使最后的数组只包含相同元素, 至少包含两个元素。

比赛的时候就是不知道剩下奇数个数的数组的时候怎么办

首先能想到 x x x ^ x = = 0 x==0 x==0,所以直接全部异或判断等不等于 0 0 0就好了结果WA了
然后就发现 x x x ^ x x x ^ x x x = = x ==x ==x 那我们就分成几个前缀异或 反正他是相邻的进行异或
记录第一次出现前缀异或为0的时候 p = i p=i p=i,这个时候异或完是 a [ n ] = = 5 a[n]==5 a[n]==5,那么在 p p p位置前面肯定有前缀异或为 5 5 5的,假如没有,那么说明是 x x x ^ x = = 0 x==0 x==0,但 a [ n ] = = 5 a[n]==5 a[n]==5就不合法。

8
1 1 1 2 2 2 3 3 WA掉了

//假算法
#include <iostream>
#define ll long long
using namespace std;
const int N = 1e6 + 9;
 ll n, m, t, p, q, a[N], x;
int main(){
    cin>>t;
    while(t--) {
        cin>>n;
        bool flag=0;
        p=0;
        for(int i=1; i<=n; i++) {
            cin>>a[i];
            a[i]^=a[i-1];
            if(a[i]==0&&!p) p=i;//记录异或为0的时候
        }
        for(int i=1; i<=p; i++) if(a[i]==a[n]) flag=1;//判断前面是否有异或相同的结果
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

C - Baby Ehab Partitions Again

题意:给你长度为 n n n的序列,问你能不能尽可能少删掉元素的个数,使这个序列不能分为两个序列之和相同的两个子序列

比赛的时候题意看错了以为是删掉最小的元素

题解就是裸的背包,删掉的元素只有一个
如果总和 s u m sum sum为奇数的时候不能平分直接cout 0
如果总和 s u m sum sum为偶数的时候并且能平分,那么我们删掉某个奇数就好了。但是没有奇数的话,我们就要找一个删掉了使他不能平分的偶数,我们把所有的数一直循环除 2 2 2 直到数列出现奇数,因为全是偶数,所有数各少一半不影响他能不能平分的结果,为了不循环,我们直接把所有数除去所有只2的最大公因子。这里都没想到。

#include <iostream>
#define ll long long
using namespace std;
ll n, m, q, a[5005], sum, dp[2000005], ans;
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
            cin>>a[i];
            sum+=a[i];
    }
    if(sum%2==1) {
        cout<<0<<endl;
        return 0;
    }
    for(int i=1; i<=n; i++){
        for(int j=sum/2; j>=a[i]; j--){
            dp[j]=max(dp[j], dp[j-a[i]]+a[i]);
        }
    }
    m=sum-dp[sum/2]*2;//两边之差为(sum-dp[sum/2])-dp[sum/2];
    if(m!=0) cout<<0<<endl;//不能平分就说明两边之差不为0
    else {
        q=a[1];
        for(int i=1; i<=n; i++) {
            q=__gcd(q, a[i]);
        }
        for(int i=1; i<=n; i++) {
            a[i]/=q;
            if(a[i]%2==1) {
                ans=i;
                break;
            }
        }
        cout<<1<<endl<<ans<<endl;
    }
    return 0;
}

D. Cut

bshd
赛后就不是很想看题了


未完

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值