Codeforces Round #696 (Div. 2)

58 篇文章 0 订阅
35 篇文章 1 订阅

A. Puzzle From the Future

题意:给定一个01串a。然后要再找一个同长度的01串b。然后把这两个串加起来,得到串d。如0110 + 1101 = 1211,然后相同的数字会合并成一个数。1211 -> 121。求出这个串b。使得串d最大。

思路:贪心。首先能+1的位置肯定先加1。那么考虑什么情况下,+1会使得串d变小。那就是 a[i]+b[i] 等于上一位的数。那么这位数就等于浪费了。第一位肯定是+1的。然后用pre上一位。遍历到 i 的时候,如果+1 会使得和前一位相同,那么就+0,反之+1。

AC代码:

#include <iostream>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
string s,s1,s2,s3;
struct node{
    int x,y;
    node(){}
    node(int xx,int yy){
        x = xx;
        y = yy;
    }
};
 
int qpow(int a,int b){
    int res = 1%mod;
    int tmp = a%mod;
    while(b) {
        if(b&1) res = res*tmp%mod;
        tmp = tmp*tmp%mod;
        b <<= 1;
    }
    return res;
}
 
bool cmp(node a1,node a2){
 
    return true;
}
 
signed main(){
    cin>>t;
    while(t--){
        cin>>n;
        cin>>s;
        int pre = 0;
        for(int i = 0 ; i < n ;i ++){
            if(s[i] == '1'){
                if(pre == 2){
                    cout<<0;
                    pre = 1;
                }else{
                    cout<<1;
                    pre = 2;
                }
            }else{
                if(pre == 1){
                    cout<<0;
                    pre = 0;
                }else{
                    cout<<1;
                    pre = 1;
                }
            }
        }
        cout<<endl;
 
    }
 
}

B. Different Divisors

题意:给出一个d,找出最小的满足条件的数。

1. 至少有四个因子。
2. 每个因子的差不小于d。

思路:首先 1 和 这个数本身,就已经有两个因子了。那么要找最小的肯定是找两个质数。然后质数1和质数2以及质数1和1的距离不大于d就行了。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 1e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
string s,s1,s2,s3;
struct node{
    int x,y;
    node(){}
    node(int xx,int yy){
        x = xx;
        y = yy;
    }
};
 
int qpow(int a,int b){
    int res = 1%mod;
    int tmp = a%mod;
    while(b) {
        if(b&1) res = res*tmp%mod;
        tmp = tmp*tmp%mod;
        b <<= 1;
    }
    return res;
}
 
bool cmp(node a1,node a2){
 
    return true;
}
int prime[700000],pcnt;
bool mark[N];
 
// 如果变量名都相同的话,就不用传参了
//void getPrimes(int prime[],int N,int &pcnt)
void getPrimes()
{
    memset(mark,0,sizeof(mark));
    mark[0] = mark[1] = 1;
    pcnt = 0;
    for(int i = 2; i < N ; i ++)
    {
        if(!mark[i])
        	prime[pcnt++] = i;
        for(int j = 0 ; i*prime[j] < N && j < pcnt ; j ++)
        {
            mark[i*prime[j]] = 1;
            if(i%prime[j] == 0)
                break;
        }
    }
}
signed main(){
    cin>>t;
    getPrimes();
    //cout<<pcnt<<endl;
    while(t--){
        cin>>n;
        int res = 1;
        int pre = 1;
        int cnt = 2;
        for(int i = 0 ; i < pcnt && cnt; i ++){
            if(prime[i]- pre >= n){
                pre = prime[i];
                res *= pre;
                cnt --;
            }
        }
        cout<<res<<endl;
    }
 
}

C. Array Destruction

题意:一个数组。起始可以选一个x。然后从数组拿出两个数加起来等于x。然后让x 等于 两个数中较大的那个。这样一直操作下去。直到拿完所有数。输出每次选择的数。无解输出NO。

思路:枚举+模拟。被我写炸了唉。一个半小时才出。第一点,就是每次必须选择当前剩下数最大的。如果不选,那么这个数就没有数可以消掉他了。所以。第一次选的肯定是最大值。剩下的枚举一个数作为第一次选择的数。一旦这两个数确定了。那么剩下结果就是固定的。O(n)模拟一下就行了。每次贪心选当前最大值。总复杂度是O(n2)的。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e3+7;
int n,m,k,t = 1,cas = 1;
//int a[N],b[N];
string s,s1,s2,s3;
int mark[N];
map<int,int> mp;
struct node1{
    int x,id;
}a[N];
 
bool cmp(node1 a1,node1 a2){
    return a1.x > a2.x;
}
 
bool check(int x,int j){
    for(int i = 1 ; i < n ; i ++){
        if(i == j) continue;
        if(!mp[a[i].x]) continue;
        if(!mp[x-a[i].x]){
            return false;
        }else{
            if(a[i].x == x-a[i].x && mp[a[i].x] == 1){
                return false;
            }
            mp[a[i].x] --;
            mp[x-a[i].x] --;
            //cout<<x<<" "<<a[i].x<<" "<<x-a[i].x<<endl;
            x = max(a[i].x,x-a[i].x);
        }
    }
    return true;
}
 
void ans(int x,int j){
    cout<<x+a[j].x<<endl;
    cout<<x<<" "<<a[j].x<<endl;
    for(int i = 1 ; i < n ; i ++){
        if(i == j) continue;
        if(!mp[a[i].x]) continue;
        mp[a[i].x] --;
        mp[x-a[i].x] --;
        cout<<a[i].x<<" "<<x-a[i].x<<endl;
        x = max(a[i].x,x-a[i].x);
    }
}
 
signed main(){
    cin>>t;
    while(t--){
        mp.clear();
        cin>>n;
        n *= 2;
        for(int i = 0 ; i < n ; i ++){
            cin>>a[i].x;
            a[i].id = i;
            mp[a[i].x] ++;
        }
        sort(a,a+n,cmp);
        int sel = -1;
        for(int j = 1; j < n ; j ++){
            mp[a[j].x] --;
            if(check(a[0].x,j)){
                sel = j;
                break;
            }
            mp.clear();
            for(int i = 1 ; i < n ; i ++){
                mp[a[i].x] ++;
            }
        }
        mp.clear();
        for(int i = 1 ; i < n ; i ++){
            mp[a[i].x] ++;
        }
        if(sel != -1){
            cout<<"YES"<<endl;
            mp[a[sel].x] --;
            ans(a[0].x,sel);
        }else{
            cout<<"NO"<<endl;
        }
    }
 
}
 

D. Cleaning

题意:一个数组。每次可以选择两个相邻的数,同时减小1。而且允许交换两个数,最多操作一次。问是否能最后全变成0。

思路:前后缀和。第一个数,肯定是和第二个数一起减。并且减到0的。同理第二个数还要和第三个数一起减。那么从左往右这样可以一直减下去。就变成了一个,a1,a2-a1,a3-a2+a1…这样的数组。存起来作为前缀和pre[],如果pre[n] == 0 则说明,减到最后大家都是0了。已经满足题意了,可以提前结束。同理,从右往左也这样进行一次。存起来作为后缀和suf[]。要保证数组都是非负数,不合法的可以进行标记。然后可以想到,如果 pre[i] == suf[i+1],那么这两个数相等。再一减。不就全变成0了嘛。因为从左往右的都清零了。从右往左也清零了。就剩这两个独苗。如果他们相等显然就全清零了。这是不交换的状态。如果交换两个数呢。如图。如果要交换的元素是a[i] 和 a[i-1],那么受到影响的就是pre[i] 和 suf[i+1]的值。具体来说,就是pre[i] = a[i+1]-pre[i-1] , suf[i+1] = a[i] - suf[i+2]。如果现在这两个值相等。也就是 pre[i] == suf[i+1],则说明交换之后,满足清零的条件了!输出YES。如果所有位置都枚举了一遍。还是不行,那就是真的不行了。输出NO。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int sel = 0;
int pre[N];
int suf[N];
 
signed main(){
    cin>>t;
    while(t--){
        cin>>n;
        for(int i = 1 ; i <= n ;i ++)
            cin>>a[i];
        for(int i=  1; i <= n ; i ++){
            if(pre[i-1] == -1 || a[i] < pre[i-1]){
                pre[i] = -1;
            }else{
                pre[i] = a[i]-pre[i-1];
            }
        }
        suf[n+1] = 0;
        for(int i = n ; i >= 1; i --){
            if(suf[i+1] == -1 || a[i] < suf[i+1]){
                suf[i] = -1;
            }else{
                suf[i] = a[i]-suf[i+1];
            }
        }
        int res = 0;
        if(pre[n] == 0) res = 1;
        for(int i = 1; i < n ; i ++){
            if(pre[i-1] == -1 || suf[i+2] == -1) continue;
            else{  // swap a[i] with a[i-1]
                if(a[i] >= suf[i+2] && a[i+1] >= pre[i-1] &&
                   a[i+1]-pre[i-1] == a[i]-suf[i+2]){
                    res = 1;break;
                }
            }
        }
        puts(res ? "YES" : "NO");
        cas++;
    }
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值