Codeforces Round #687 (Div. 2, based on Technocup 2021 Elimination Round 2)

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

A. Prison Break

题意:越狱。n*m的地图中,每个点上有一个人,地图中有个洞。要所有人移动到洞的位置。一次只能移动到相邻位置。问最少要多长时间。

思路:求最远的点到他的距离就行了。最远的肯定是四个角的点。

AC代码:

#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];
 
signed main(){
    cin>>t;
    while(t--){
        int x,y;
        cin>>n>>m>>x>>y;
        int res = max(abs(n-x)+abs(m-y),abs(1-x)+abs(1-y));
        res = max(res,abs(1-x)+abs(m-y));
        res = max(res,abs(n-x)+abs(1-y));
        cout<<res<<endl;
    }
    return 0;
}

B. Repainting Street

题意:一个数组每个值表示不同颜色。每次可以把连续的k个刷成同一个颜色。问最少刷多少次可以刷成全部一样的颜色。

思路:颜色总数很少。就100种。暴力枚举刷成每种颜色需要的最少次数。然后暴力模拟就好了。

AC代码:

#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];
vector<int> v1;
map<int,int> mp;
 
int cal(int x){
 
    int res = 0;
    for(int i = 0 ; i < n ; i ++){
        if(a[i] != x ){
            res ++;
            i += m-1;
        }
    }
    return res;
 
}
signed main(){
    cin>>t;
    while(t--){
        cin>>n>>m;
        v1.clear();
        mp.clear();
        int maxx = 0;
        int maxi = 0;
        for(int i = 0 ; i < n ; i ++){
            cin>>a[i];
            mp[a[i]] ++;
            if(mp[a[i]] == 1) v1.push_back(a[i]);
        }
        int res = 1e18;
        for(int i = 0 ; i < v1.size() ; i ++){
            res = min(res,cal(v1[i]));
        }
        cout<<res<<endl;
    }
    return 0;
}

C. Bouncing Ball

题意:n个格子,有的格子为空。第一次会跳到 p 格子,然后会跳到 p+k, p+2k, p+3k … 。两种操作。要么填补一个空格子,代价x。要么删掉最前面的一个格子。剩下的格子往前移。代价y。问最少花费多少代价。可以使得球从开始一直弹,弹到结束。

思路:首先因为每次要跳k个格子。那肯定位置和 id%k有关。 假设前面一个都没有删掉。那么就要保证,p 以及所有的 p+k,p+2k不为空。也就是 (id-p)%k == 0 的位置不为空。那如果删掉一个呢。删掉一个 等于后面的所有 id-1, 也就是要求(id-1-p)%k == 0,也就是相当于(id-p)%k == 1的位置不为空。 所以开局先记录下每个余数的出现次数。然后枚举删掉前面x个格子。剩下的格子 有几个需要填的。就是模拟了。

AC代码:

#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];
map<int,int> mp;
 
signed main(){
    cin>>t;
    while(t--){
            int p;
        cin>>n>>p>>k;
        string s;
        cin>>s;
        int x,y;
        cin>>x>>y;
        mp.clear();
        for(int i = 0 ; i < s.size() ; i ++){
            if(s[i] == '1'){
                if(i+1 > p)
                    mp[(i+1-p)%k] ++;
            }
        }
        int now = 0;
        int need = (n-p)/k;
        int have = mp[now];
        int tmp = (need-have+(s[p-1] == '0'))*x;
        int res = tmp;
        //cout<<tmp<<endl;
        for(int i = 0 ; i  < n ; i ++){
            now = (now+1)%k;
            if(p+i >= n) break;
            if(s[i+p] == '1'){
                mp[(i+p+1-p)%k] --;
            }
            need = (n-p-i-1)/k;
            have = mp[now];
            //cout<<need<<" "<<have<<endl;
            tmp = (need-have+(s[p+i] == '0'))*x + y*(i+1);
            res = min(res,tmp);
            //cout<<tmp<<endl;
        }
        cout<<res<<endl;
    }
    return 0;
}

D. XOR-gun

题意:原来的非递减的一个数组。现在有一种操作。可以选择相邻的两个数。用异或值替换这两个数。问最少多少次操作使得数组 不是非递减的。

思路:要想到一个结论就可以写了。如果有连续三个数的最高位为1,那么肯定异或后面两个数。不就比第一个数小了嘛。所以答案就是1。但是数据范围只有 1e9。也就是2进制最多不超过 30 位。并且又是递增的数组。那么如果数组长度大于 60。必然会出现连续的三个最高位为1 的情况。 所以直接输出1。 小于60 就暴力枚举就好了。

AC代码:

#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];
map<int,int> mp;
 
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 ++){
            b[i] = a[i]^b[i-1];
        }
        int res = 1e18;
        for(int i = 1 ; i <= n ; i ++){
            for(int j = i ; j-i <= 32 && j <= n ; j ++){
                for(int k = j+1 ; k-j <= 32  && k <= n; k ++){
                    if( (b[j]^b[i-1]) > (b[k]^b[j])){
                        //cout<< (b[j]^b[i-1])<<" "<<(b[k]^b[j])<<endl;
                        //cout<< ((b[j]^b[i-1]) > (b[k]^b[j])) <<endl;
                        res = min(res,k-j-1 + j-i);
                    }
                }
            }
        }
        if(res > 1e9) cout<<-1<<endl;
        else
            cout<<res<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值