AtCoder Beginner Contest 380 题解A-E

AtCoder Beginner Contest 380 - AtCoder

A - 123233

题目及数据范围:

思路:字符串读入,用三个变量统计123的出现次数然后判断合不合法。

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll n , m;

void solve(){
    std::string s;
    std::cin >> s;
    ll a = 0, b = 0, c = 0;
    for (ll i = 0; i < s.length(); i++){
        if(s[i] == '1') a++;
        if(s[i] == '2') b++;
        if(s[i] == '3') c++;
    }
    if(a == 1 && b == 2 && c == 3) {
        std::cout << "Yes" << '\n';
    } else std::cout << "No" << '\n';
}

signed main(){  
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

 B - Hurdle Parsing

题目及数据范围:

思路:

给你一个字符串,输出每个‘|’之间‘-’的数量。比较简单,直接找到一个|后就接着找有几个连续的-就可以,方法有很多种。

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
std::string s;
ll cnt = 0;
ll ans[N];

void solve(){
    std::cin >> s;
    for (ll i = 0; i < s.length(); i++){
        if(s[i] == '|'){
            ll j = i + 1;
            cnt++;
            ll sum = 0;
            while(j < s.length() && s[j] != '|') sum++ , j++;
            ans[cnt] = sum;
            i = j - 1;
        }
    }
    for (ll i = 1; i < cnt; i++) std::cout << ans[i] << ' ';
}

signed main(){  
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

 C - Move Segment

思路:很多人被长题目误导了,其实题目非常简单。找第k个连续的1段,然后整体移动到k-1段后面。可以存下当前段的歧视位置和长度,和上一段的位置和长度,然后找到第k段后,就把当前段复制,删除,再从前一段末尾插入就可以了。 

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll n , k;
std::string s;

void solve(){
    std::cin >> n >> k;
    std::cin >> s;
    ll pos1 = 0;
    ll pos2 = 0;
    ll pos3 = 0;
    ll pos4 = 0;
    ll now = 0;
    for (ll i = 0; i < s.length(); i++){
        if(s[i] == '1'){
            if(now >= k) break;
            ll j = i; 
            now++;
            while(j < s.length() && s[j] == '1') j++;
            pos3 = pos1;
            pos4 = pos2;
            pos1 = i;
            pos2 = j - 1;
            i = j;
        }
    }
    //std::cout << pos1 << '\n';
    //std::cout << pos3 << '\n';
    std::string temp = s.substr(pos1 , pos2 - pos1 + 1);
    s.erase(pos1 , pos2 - pos1 + 1);
    s.insert(pos4 , temp);
    std::cout << s << '\n'; 
}

signed main(){  
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

D - Strange Mirroring 

思路:长度特别长,不可能直接模拟。考虑到长度是倍增的。我们可以每次从当前串的前半部分找生成要查询位置的原串,递归查找。每次找这个串的中间位置,根据他们的距离,找到前半部分的原位置。直到找到小于等于原串长度的位置,就是生成要找的位置的那个字符。然后我们dfs的时候记录当前第几次,根据层数的奇偶判断要不要大小写转换。

不用int128.但是当时没想那么多

(使用快读务必把流同步打开)

每个查询是在减半,所以总复杂度nlogn

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
std::string s;
ll q;
__int128 k[N];
__int128 mi[70];
ll maxx = 0;

inline void read(__int128 &n){
    __int128 x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    n=x*f;
}

inline void print(__int128 n){
    if(n<0){
        putchar('-');
        n*=-1;
    }
    if(n>9) print(n/10);
    putchar(n % 10 + '0');
}

char dfs(ll cnt , ll now){
    if(now <= s.length()){
        if(cnt % 2 == 0)return s[now - 1];
        else {
            if(s[now - 1] >= 'a' && s[now - 1] <='z') return (char)(s[now - 1] - 32);
            else return (char)(s[now - 1] + 32);
        }
    }
    ll pos = std::lower_bound(mi + 1 , mi + 1 + maxx , now) - mi;
    pos--;
    ll neww = now - mi[pos];
    return dfs(cnt + 1 , neww);
}

void solve(){
    std::cin >> s;
    std::cin >> q;
    mi[1] = s.length();
    for (ll i = 2; i <= 64; i++){
        if(mi[i - 1] * 2 > 1e18){
            maxx = i - 1;
            break;
        }
        mi[i] = 2 * mi[i - 1];
    }
    for (ll i = 1; i <= q; i++) read(k[i]);
    for (ll i = 1; i <= q; i++){
        std::cout << dfs(0 , k[i]) << ' ';
    }
}

signed main(){  
    //std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

E - 1D Bucket Tool

题目:

思路:

看着很像数据结构题。考虑到每次要把同颜色的看成一个整体,联想到并查集。我们给整个区间分成n个段。每次合并我们把每个段合并在一起。每个大段找一个点当父亲,这样子修改操作时就可以找到大段。每次修改记得看一下前后相邻的段颜色是否一样,一样就可以合并。然后每次统计下修改后,原来颜色少了多少,新颜色多了多少,再O1输出。

复杂度大概是Oq。

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll n , q;
ll fa[500005];
ll shu[500005];

ll find(ll x){
    if (fa[x] == x) return fa[x];
    else return fa[x] = find(fa[x]);
}

struct Qujian{
    ll l , r , se;
}qujian[500005];

void solve(){
    std::cin >> n >> q;
    for (ll i = 1; i <= n; i++) shu[i] = 1;
    for (ll i = 1; i <= n; i++) {
        fa[i] = i;
        qujian[i].l = i;
        qujian[i].r = i;
        qujian[i].se = i;
    }
    while (q--){
        ll opt;
        std::cin >> opt;
        if (opt == 1){
            ll x , c;
            std::cin >> x >> c;
            ll a = find(x);
            shu[qujian[a].se] -= qujian[a].r - qujian[a].l + 1;
            qujian[a].se = c;
            shu[qujian[a].se] += qujian[a].r - qujian[a].l + 1;
            ll zuo = find(qujian[a].l - 1);
            ll you = find(qujian[a].r + 1);
            if(qujian[a].l - 1 >= 1 && qujian[a].se == qujian[zuo].se){
                fa[zuo] = a;
                qujian[a].l = qujian[zuo].l;
            }
            if(qujian[a].r + 1 <= n && qujian[a].se == qujian[you].se){
                fa[you] = a;
                qujian[a].r = qujian[you].r;
            }
            //std::cout << qujian[a].l << ' ' << qujian[a].r << '\n';
        } else {
            ll c;
            std::cin >> c;
            std::cout << shu[c] << '\n';
        }
    }
}

signed main(){  
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值