牛客练习赛121(上 ABC) 题解

牛客练习赛121(上 ABC) 题解

代码风格

后续目标代码写在solve()方法中

#include<bits/stdc++.h>
//#include<iostream>
//#include<vector>
//#include<cstdio>
//#include<cmath>
//#include<cstring>
​
using namespace std;
#define ll long long
#define endl "\n"
​
const int N = 2e5 + 10;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int INF = 1e9;
const int MAXN = 2020;
const int mod = 1e8 + 7;
​
int prime[N];
void check() {
    memset(prime, 0, sizeof(prime)); //0 素数 1 不是素数
    prime[1] = 1;
    for (int i = 2; i <= N; i++) {
        if (prime[i] == 0) {
            for (int j = i * 2; j <= N; j += i) {
                prime[j] = 1;
            }
        }
    }
}
​
bool cmp(int x, int y) {
    return x > y;
}
​
void solve() {
​
}
​
int main() {
    //  freopen("input.txt","r",stdin);
    //  freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    //  cin.ignore() ;
    //  cin.clear();
    //t = 1;
    //check();
    //这里根据具体情况来变动t,是输入还是默认为1
    while ( t--) {
        solve();
    }
}

A.小念吹气球

思路

题目分析后可以知道,这是将字母-数字进行创建键值对的方式,那么首次出现的字母对应的值就可以+2,其次+1即可,所以我们可以采用两种方式,一种是简单的静态固定大小数组即可解决,另一种我们采用键值对的形式即可完成

AC代码
//静态数组方式,因为是26个字母,所以进行-'a'或者-'A'来实现,但是如果同时存在就不行了
void solve() {
    int n;
    cin>>n;
    string str;
    cin>>str;
    int s[27]={0};
    ll sum=0;
    for(int i=0;i<n;i++){
        if(s[str[i]-'A']==0){
            sum+=2;
            s[str[i]-'A']++;
        }else {
            sum+=1;
            s[str[i]-'A']++;
        }
    }
    cout<<sum<<endl;
}
​
//使用stl的map方法直接解决
void solve() {
    int n;
    cin>>n;
    string str;
    cin>>str;
    map<char,int>mp;
    ll ans=0;
    for(int i=0;i<n;i++){
        if(mp.find(str[i])==mp.end()){//如果找不到
            ans+=2;
            mp.insert(make_pair(str[i],1));//使用make_pair方法或者直接裸键值对
            //mp.insert({str[i],1});
        }else{
            ans+=1;
            mp[str[i]]++;
            //mp.at(str[i])++;
        }
    }
    cout<<ans<<endl;
​
}
​
​

B.You Brought Me A Gentle Breeze on the Field

思路

题目分析后可以猜测该问题是博弈问题,那么对于此类博弈,一般从简单情况进行上推,而后利用贪心的方法进行破解,隧而求解,这里具体的解释,我放在了代码里,从简单形式,从后往前倒退等形式是十分关键的点

AC代码
void solve() {
    int n,m,p;
    cin>>n>>m>>p;
    /*
      简单情况:
      1,先手方为连取方直接获胜 即 n>=2+1&&n<=2*m+1
      2,先手方不为连取方获胜即 n>=1+1&&n<=m+1
      3,n=1时 必然后手获胜 n=2时 必然先手获胜
      
      分析可以知道,想要获胜必然是达到上述的简单步骤的时候才行
      所以二者都在很聪明的情况下,都会去避免对方进入这个情况,所以一旦n很大的时候
      都只会一个一个地取 这样结果就明朗了
     */
    if(n==1){
        cout<<"YangQiShaoNian"<<endl;
        return;
    }
    if(n==2){
        cout<<"XiaoNian"<<endl;
        return;
    }
    if(p==0){
        //xiaonian有连取机会
        //那么n>2m+1后 每个人都只能1个1个来取
        //而根据简单规则  即可得到
        if(n>=3&&n<=2*m+1){
            cout<<"XiaoNian"<<endl;
            return;
        }else{
            //2m+1  >m+1  所以一个一个取一定是先达到连取方的破局点
            cout<<"XiaoNian"<<endl;
            return;
        }
    }else{
        //YangQiShaoNian有连取机会
        if(n>=2&&n<=m+1){
            cout<<"XiaoNian"<<endl;
            return;
        }else{
                //2m+1  >m+1  所以一个一个取一定是先达到连取方的破局点
            cout<<"YangQiShaoNian"<<endl;
            return;
        }
    }
}
​

C.氧气少年的水滴 2

思路

首先题意很容易读懂,那么如何处理是问题关键,我们观察数据可以发现测试案例与单次测试总量均在10^5数量级,那么意味着我们每一次的复杂度最多是O(n),所以我们分析完,可以采用模拟的方法进行即可,因为只有一滴水滴,所以一加之后,我们利用标记变量进行标记,然后左右变化即可,每一次有水滴后,我们从滴落点开始,每次分别用两个指针进行判断,这样复杂度就是O(n)

AC代码
//我这里写的是比较粗糙的,因为我当时考虑的是左一个右一个来处理,这样代码就很复杂了
void solve() {
    int n, p;
    int sd[N];
    cin >> n >> p;
    for (int i = 1; i <= n; i++)cin >> sd[i];
    int lnum = 0, rnum = 0;//标识此刻左右漂浮的水滴数量
    int ptr = p;
    sd[ptr]++;
    if (sd[ptr] == 10) {
        lnum++;
        rnum++;
        for (int i = ptr - 1, j = ptr + 1; i > 0 || j <= n;) {
            if (lnum == 0 && rnum == 0) { //这可以是一个结束条件,没有浮动的雨滴了
                cout << "0 0" << endl;
                return;
            }
            if (rnum != 0 && j > n && lnum == 0) {//提前终止,左结束,右存在
                cout << lnum << " " << rnum << endl;
                return;
            }
            if (lnum != 0 && i < 1 && rnum == 0) {//提前终止,左存在,右结束
                cout << lnum << " " << rnum << endl;
                return;
            }
            if (i > 0) {
                if (lnum > 0) {
                    if (sd[i] + lnum >= 10) {//如果>=10 水滴就要破裂了
                        lnum = sd[i] + lnum - 10;
                        i--;
                        lnum++;
                        rnum++;
                    } else {//否则没有破裂就得把漂浮的水滴清空
                        sd[i] += lnum;
                        lnum = 0;
                    }
                }
​
            }
            if (j <= n) {//右侧同理
                if (rnum > 0) {
                    if (sd[j] + rnum >= 10) {
                        rnum = sd[j] + rnum - 10;
                        j++;
                        lnum++;
                        rnum++;
                    }else {
                        sd[j] += rnum;
                        rnum = 0;
                    }
                } 
​
            }
​
        }
        cout << lnum << " " << rnum << endl;
    } else {
        cout << "0 0" << endl;
    }
​
​
}
​
//一次性代码处理,极简版本
​
void solve() {
    int n,p;
    int sd[N];
    cin>>n>>p;
    for(int i=1;i<=n;i++)cin>>sd[i];//这里从1开始,方便计数
    int lnum=0,rnum=0;//这里还除去了左右平行水滴不相撞的情况,如果相撞,增加标记变量即可
    //lrnum  llnum  rlnum  rrnum  分别表示左的左右水滴  右边的左右水滴  最后抵消即可
    sd[p]++;
    if(sd[p]==10){
        lnum++;
        rnum++;
        int i=p-1,j=p+1;//两个指针指向一左一右
        while((i>=1&&lnum>0)||(j<=n&&rnum>0)){//大循环结束条件是左右都遍历结束
            //左继续  i>=1&&lnum>0
            //右继续  j<=n&&rnum>0
            //分别进行判断即可
            while(i>=1&&lnum>0){//左边判断
                if(sd[i]+lnum>=10){
                    lnum=sd[i]+lnum-10;
                    i--;
                    lnum++;
                    rnum++;
                }else{
                    sd[i]+=lnum;
                    lnum=0;
                }
            }
            while(j<=n&&rnum>0){//右边判断
                if(sd[j]+rnum>=10){
                    rnum=sd[j]+rnum-10;
                    j++;
                    lnum++;
                    rnum++;
                }else{
                    sd[j]+=rnum;
                    rnum=0;
                }
            }
        }
    }
    cout<<lnum<<" "<<rnum<<endl;
}
​

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值