Codeforces Round #807 (Div. 2)

Dashboard - Codeforces Round #807 (Div. 2) - Codeforcesicon-default.png?t=M666https://codeforces.com/contest/1705。。。9点场看成10点场,拿小号打最后一小时,按速度来说应该能吃分的。。。

A. Mark the Photographer

排序以后直接模拟判断就好了

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e3+10;
int num[maxn];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n,x;
        cin>>n>>x;
        for(int i = 1;i<=n*2;i++)
            cin>>num[i];
        sort(num+1,num+2*n+1);
        int j = 1;
        for(int i = 1;i<=n;i++)
            if(num[i+n]-num[i]<x){
                j = 0;
                break;
            }
        if(j)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
}

B. Mark the Dust Sweeper

贪心一下,最理想的情况肯定是每个房间-1,最后一个房间+1,为了达成这种情况就把最左边非0房间到最后一个房间之间为0的房间操作一下,比如 0 2 0 2 先变成 0 1 1 2然后第二个第三个房间的内容都能直接扔到最后一个房间

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i = 1;i<=n;i++)
            cin>>num[i];
        long long ans = 0;
        int j = 0;
        int nn = 0;
        for(int i = 1;i<n;i++){
            if(!j&&num[i]>0){
                j = 1;
            }
            if(j&&num[i]==0)
                nn++;
        }
        for(int i = 1;i<n;i++)
            ans+=num[i];
        ans+=nn;
        cout<<ans<<endl;
    }
}

C. Mark and His Unfinished Essay

这题的思路属于一个函数映射,基础条件是c很小。如果询问的下标在起始长度内,可以直接得到答案,如果不是,就要一层层映射回去直到找到原始字符串的位置。比如样例的markmark(1-4复制一次),我询问下标6,根据复制了1-4可知,下标6是映射了下标2的内容。具体映射函数关系为先二分找到对应下标i是在哪一次复制中产生的,再减去前一次复制的最终长度+1,再加上本次对应复制范围的起始下标。比如上述提到的2 = 6-(4+1)+1。绘图理解一下最好。

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n,c,q;
        cin>>n>>c>>q;
        string s;
        cin>>s;
        long long l,r;
        long long len[100] = {};
        pair<long long,long long>ch[100] = {};
        len[1] = n;
        int tar = 1;
        for(int i = 1;i<=c;i++){
            cin>>l>>r;
            ch[tar] = {l,r};
            len[tar+1] = r-l+len[tar]+1;
            ++tar;
        }
        for(int i = 1;i<=q;i++){
            cin>>l;
            long long now = l;
            while(now>n)
            {
                int pos = lower_bound(len+1,len+tar+1,now)-len;
                pos--;
                now = now-len[pos]-1+ch[pos].first;
                //cout<<now<<" "<<len[pos]<<" "<<ch[pos].first<<endl;
            }
            cout<<s[now-1]<<endl;
        }
    }
}

D. Mark and Lightbulbs

补出来的。这个操作其实可以看成,它可以衍生1串,即01000可以变成01100也可以变成00100,

就是可以把它变长/变短/移动,但是不能分裂,即 01000 不能变成01010这种情况

然后-1的情况就两种,1串个数不同/首尾不同。

再考虑操作次数,在纸上模拟一下就发现,是1串首尾长度-对应1串首尾长度。

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--) {
        int n;
        cin >> n ;
        string s1,s2;
        cin>>s1>>s2;
        vector<pair<int,int>>v1,v2;
        if(s1[0]!=s2[0]||s1[n-1]!=s2[n-1]){
            cout<<-1<<endl;
            continue;
        }
        int j = 0;
        for(int i = 0;i<n;i++){
            if(s1[i]=='1'&&j==1){
                v1.back().second++;
            }
            else if(s1[i]=='1'&&j==0){
                v1.push_back({i,i});
                j = 1;
            }
            if(s1[i]=='0'&&j==1){
                j = 0;
            }
        }
        j = 0;
        for(int i = 0;i<n;i++){
            if(s2[i]=='1'&&j==1)
                v2.back().second++;
            if(s2[i]=='1'&&j==0){
                v2.push_back({i,i});
                j = 1;
            }
            if(s2[i]=='0'&&j==1){
                j = 0;
            }
        }
        if(v1.size()!=v2.size()){
            cout<<-1<<endl;
            continue;
        }
        long long ans = 0;
        for(int i = 0;i<v1.size();i++){
            ans+=abs(v1[i].first-v2[i].first);
            ans+=abs(v1[i].second-v2[i].second);
        }
        cout<<ans<<endl;
    }
}
//这个操作最终能实现的是1串伸长/简短/移动
//为什么不考虑0串:01串 1串动0也动,相对的
//次数怎么算:按最快考虑 01000->00100要两次,01100->00110要2次,即1串首位-变后1串首位取abs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值