Codeforces Round 905 (Div. 3)

Codeforces Round 905 (Div. 3)

A. Morning

模拟,rating 800

题干

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

设一个now=1

next=s[0]

先不算点击的代价,只算移动的代价:

不断用next-now,取绝对值累加起来即可。

注意把0换成10

然后再加4下点击的代价。

#include<bits/stdc++.h>
using namespace std;

#define int long long

void slove(){
    string s;
    cin>>s;
    int cnt=0;
    vector<int> a;
    int len=s.size();
    a.push_back(1);
    for(int i=0;i<len;i++){
        int t=(int)(s[i]-'0');
        if(s[i]=='0')a.push_back(10);
        else a.push_back(t);
    }
    for(int i=1;i<5;i++){
        cnt+=abs(a[i]-a[i-1]);
    }
    cnt+=4;
    cout<<cnt<<endl;
}

signed main(){

    int t;
    cin>>t;
    while(t--){
        slove();
    }
}

B. Chemistry

字符串处理 rating 800

回文字符串特征:

里面的字符出现奇数次的至多只有一种。

所以我们先统计出现奇数次的字符有多少次,设为cnt。

因为我们能删掉k个字符。

所以若k>cnt,那么多出来的用偶数次的抵消即可。

若k==cnt,剩下的全是偶数次

若k<cnt,若cnt-k>1,则无法构成回文

#include<bits/stdc++.h>
using namespace std;

#define int long long

void slove(){
    int n,k;
    cin>>n>>k;
    string s;
    cin>>s;
    map<char,int > m;
    for(int i=0;i<s.size();i++){
        m[s[i]]++;
    }
    
    int ji=0;
    for(auto i:m){
        if(i.second &1)ji++;
    }
    
    if(k>ji){
      cout<<"YES"<<endl;
    }
    else if(k==ji){
        cout<<"YES"<<endl;
    }
    else{
        ji-=k;
        if(ji>1){
            cout<<"NO"<<endl;
        }
        else {
            cout<<"YES"<<endl;
        }
    } 
}


signed main(){

    int t;
    cin>>t;
    while(t--){
        slove();
    }
}

C. Raspberries

数学,分类讨论 rating 1000

数字之积能被k整除的特征:

  1. 有一个数字是k或k的倍数
  2. 这些数字里有k的所有质因数

由于 2 ≤ k ≤ 5 2\leq k\leq5 2k5,只有4不是质数。

所以分为k==4 和k!=4讨论即可。

对于k!=4,只需要取模k找余数离k最近的即可。

对于k==4, 因为任何数不是偶数就是奇数,所以计算奇数偶数个数即可。

当偶数超过2个,或者存在4,答案为0.

当偶数只有一个,且奇数大于1个,则答案为1

当没有有数,如果有3,那么答案为1

如果没有3,那么答案为2

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define ll long long

void slove(){
    int n,k;
    cin>>n>>k;
    vector<int> a(n);
    for(int i=0;i<n;i++)cin>>a[i];
    
    int cnt=10;
    for(int i=0;i<n;i++){
        if(a[i]%k==0){
            cout<<0<<endl;
            return;
        }
        cnt=min(cnt, k-a[i]%k);
    }
    if(k==4){
        int ji=0;
        int ou=0;
        for(int i=0;i<n;i++){
            if(a[i]%2==0){
                ou++;
            }
            else{
                ji++;
            }
        }
        if(ou>=2){
            cout<<0<<endl;
            return;
        }
        else if(ou>=1){
            int t=min(1ll,cnt);
            cout<<t<<endl;
            return;
        }
        else {
            cout<<min(2ll,cnt)<<endl;
            return;
        }
    }
    cout<<cnt<<endl;
}

signed main(){

    int t;
    cin>>t;
    while(t--){
        slove();
    }
}

D. In Love

贪心 rating 1500

题目比较仁慈,只要我们的集合里面有不相交的线段,就输出yes。

所以只有全都是相交的线段时,才输出NO。

我们想想不相交条件:

存在 l i > r j ( i ! = j ) l_i>r_j(i!=j) li>rj(i!=j)

很容易想到高中数学的任意存在问题:

那么就是: l m a x > r m i n l_{max}>r_{min} lmax>rmin即可

然后随意选择一个数据结构,支持增删改查的。

multiset

最大值:*rbegin()

最小值:*begin()

查:find()

删:erase()

增:insert()

由于存在集合为空的情况。

所以使用这些函数的条件是集合不为空

所以我们特判一下集合为空的情况输出NO即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define ll long long

void slove() {
    int q;
    cin >> q;
    multiset<int> ql, qr;
    while (q--) {
        char ch;
        cin >> ch;
        int l, r;
        cin >> l >> r;

        if (ch == '+') {
            ql.insert(l);
            qr.insert(r);
            if (!ql.empty() && !qr.empty()) {
                int maxl = *ql.rbegin();
                int minr = *qr.begin();
                if (maxl > minr)
                    cout << "YES" << endl;
                else
                    cout << "NO" << endl;
            }
        } else {
            if (ql.find(l) != ql.end())
                ql.erase(ql.find(l));
            if (qr.find(r) != qr.end())
                qr.erase(qr.find(r));
            if (!ql.empty() && !qr.empty()) {
                int maxl = *ql.rbegin();
                int minr = *qr.begin();
                if (maxl > minr)
                    cout << "YES" << endl;
                else
                    cout << "NO" << endl;
            }
            else{
                cout<<"NO"<<endl;
            }
        }
    }
}

signed main() {
    slove();
    return 0;
}

E. Look Back

构造,数学

思路很简单,对于a[i],如果a[i]<a[i-1],那么不断乘2直到大于a[i-1]即可

但是数很大会tle 和爆longlong

所以我们再创建一个数组s[i]

含义是:应该比a[i-1]乘上多少个2

若a[i]<a[i-1]
先算原始该乘的2,再加上s[i-1]
若a[i]>a[i-1]
先计算原始可以少乘的2,若大于s[i-1]那么令为0
否则加上s[i-1]

#include<bits/stdc++.h>
using namespace std;
#define  ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr) 
#define int long long
#define ll long long
const int N=1e5;
int a[N];
void slove() {
   int n;
   cin>>n;
   
   for(int i=0;i<n;i++){
       cin>>a[i];
   }
   
   
   vector<int> add(n);
  
  
   for(int i=1;i<n;i++){
       
       if(a[i]<a[i-1]){
           
           //原始的a[i]<a[i-1],意义是,a[i]应该乘以多少个2才能不小于a[i-1]
           //算出原始的add[i]---应该乘多少个2
           
           //向上取整后的商:
           int int_shang=(a[i-1]+a[i]-1)/a[i]; //先算出应该乘的数向上取整
          
           
           //由于只能乘2的次方,所以找出至少乘2的多少次方
           //如果二进制的最高位不等于最低位,那么多乘一次
           //二进制的最高位
           int max_pos=log2(int_shang); 
           //二进制的最低位
           int min_pos= (int_shang)&(-int_shang);
           min_pos=log2(min_pos);
           
        
           //此时算出来的是原始的a[i]到原始的a[i-1]应该乘的2的次方
           if(max_pos==min_pos){
               add[i]=max_pos;
             //  cout<<add[i]<<endl;
           }
           else{
               add[i]=max_pos+1;
           }
           
           //若a[i-1]到a[i-2]也需要乘,那么我们就直接累加
           add[i]+=add[i-1]; 

       }
       
       else if(a[i]==a[i-1]){
           add[i]+=add[i-1];
       }
       else{ //a[i]>a[i-1],计算需要少乘多少次2
           if(add[i-1]==0)continue;
           int int_shang=a[i]/a[i-1]; 
           int min_pos= log2(int_shang);
           if(min_pos>add[i-1])continue;
           add[i]=-min_pos;
           add[i]+=add[i-1];
           
       }
       
      
       
   }
   int cnt=0;
   for(int i=0;i<n;i++){
      cnt+=add[i];
   }
   cout<<cnt<<'\n';
}

signed main() {
    ios;
    int T;
    cin>>T;
    while(T--){
      slove();
    }
    return 0;
}

int int_shang=a[i]/a[i-1];
int min_pos= log2(int_shang);
if(min_pos>add[i-1])continue;
add[i]=-min_pos;
add[i]+=add[i-1];

   }

}
int cnt=0;
for(int i=0;i<n;i++){
cnt+=add[i];
}
cout<<cnt<<‘\n’;
}

signed main() {
ios;
int T;
cin>>T;
while(T–){
slove();
}
return 0;
}


  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

louisdlee.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值