abc372题解(A-E)

比赛链接:b​​​​​UNIQUE VISION Programming Contest 2024 Autumn (AtCoder Beginner Contest 372) - AtCoder

A - delete . 

翻译:给你一个由小写英文字母和 . 组成的字符串 S 。请找出从 S 中删除所有 . 后得到的字符串。

思路:直接读入字符串s,枚举每个字符,如果是.就跳过,不是则输出。、

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,m,q,k,t;
int num[2000005];
string s;

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>s;
    for(int i=0;i<s.length();i++){
        if(s[i]=='.') continue;
        cout<<s[i];
    }
    return 0;
}

B - 3^A 

题目如图

思路:贪心,枚举单次最大可能的Ai,然后把目标值m减去这个数;因为题目保证可以相等,所以退出循环条件设置成m=0即可(刚好被减完)。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,m,q,k,t;
int num[2000005];
int ans[2000005];
int ansnum=0;

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>m;
    int cnt=0;
    int ppp=15;
    while(m!=0){//m=0就退出循环了
        ppp=10;//指数,从大到小保证最大。
        while(ppp>=0){
            cnt=pow(3,ppp);
            if(cnt<=m){//如果3的ppp次方小于m,则这个ppp必然是其中一个答案
                m-=cnt;
                ans[++ansnum]=ppp;//存每个答案
                break;
            }
            ppp--;
        }
    }
    cout<<ansnum<<endl;
    for(int i=ansnum;i>=1;i--) cout<<ans[i]<<" ";
    return 0;
}

C - Count ABC Again

题目与数据范围:

思路:考虑到每次只修改一个字符,对答案的影响最多只有1。

所以遍历初始字符串,统计一共出现几次。之后每次修改,判断对答案是否有影响,只需要看这个修改的点附近几个点的数据就可以。

复杂度O\left ( N+Q \right )

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,q;
string s;
int tag[2000005];

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>q;
    string ss;
    s+="*";
    cin>>ss;
    s+=ss;
    //cout<<s<<endl;
    int cnt=0;
    int len=s.length();
    for(int i=1;i<=len-2;i++){
        if(s[i]=='A' && s[i+1]=='B' && s[i+2]=='C'){
            cnt++;
            tag[i]=1;
            tag[i+1]=1;
            tag[i+2]=1;
        }
    }//初始化记录cnt,tag数组用来标记这个点是不是abc字串。
    //cout<<cnt<<endl;
    while(q--){
        int a;char b;
        cin>>a>>b;
        if(tag[a]==1){//如果修改的点原先是字串的一个字符
            cnt--;//先默认答案减少一个
            if(s[a]=='A'){//要修改的点是ABC的哪一个?
                bool flag=false;
                tag[a]=0;
                tag[a+1]=0;
                tag[a+2]=0;
                s[a]=b;
                for(int i=a-2;i<=a;i++){
                    if(i<1 || i+2>len) continue;
                    if(s[i]=='A' && s[i+1]=='B' && s[i+2]=='C'){
                        cnt++;
                        tag[i]=1;
                        tag[i+1]=1;
                        tag[i+2]=1;
                        flag=true;
                        cout<<cnt<<endl;
                        break;
                    }
                }
                if(flag==false) cout<<cnt<<endl;
                continue;
            }
            if(s[a]=='B'){
                bool flag=false;
                tag[a-1]=0;
                tag[a]=0;
                tag[a+1]=0;
                s[a]=b;
                for(int i=a-2;i<=a;i++){
                    if(i<1 || i+2>len) continue;
                    if(s[i]=='A' && s[i+1]=='B' && s[i+2]=='C'){
                        cnt++;
                        tag[i]=1;
                        tag[i+1]=1;
                        tag[i+2]=1;
                        flag=true;
                        cout<<cnt<<endl;
                        break;
                    }
                }
                if(flag==false) cout<<cnt<<endl;
                continue;
            }
            if(s[a]=='C'){
                bool flag=false;
                tag[a-2]=0;
                tag[a-1]=0;
                tag[a]=0;
                s[a]=b;
                for(int i=a-2;i<=a;i++){
                    if(i<1 || i+2>len) continue;
                    if(s[i]=='A' && s[i+1]=='B' && s[i+2]=='C'){
                        cnt++;
                        tag[i]=1;
                        tag[i+1]=1;
                        tag[i+2]=1;
                        flag=true;
                        cout<<cnt<<endl;
                        break;
                    }
                }
                if(flag==false) cout<<cnt<<endl;
                continue;
            }

        } else {//如果不是,修改后,看看前后能不能达成新的子串
            bool flag=false;
            s[a]=b;
            for(int i=a-2;i<=a;i++){
                if(i<1 || i+2>len) continue;
                if(s[i]=='A' && s[i+1]=='B' && s[i+2]=='C'){
                    cnt++;
                    tag[i]=1;
                    tag[i+1]=1;
                    tag[i+2]=1;
                    flag=true;
                    cout<<cnt<<endl;
                    break;
                }
            }
            if(flag==false) cout<<cnt<<endl;
        }
    }
    return 0;
}

D - Buildings

题目与数据范围

思路:单调数据结构。这里用单调栈。

要求i到j之间没有比j高的,那就把栈内比j小的元素统统出栈,直到遇到第一个比j高的。而这个数能给i到j之间所有的数增加一个贡献。

复杂度O\left ( N \right )

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#define int long long
#define endl '\n'
using namespace std;
int chafen[200005];
int n;
stack<pair<int,int>> s;

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n;
	pair<int,int> temp;//first存数字,second存位置。
	s.push({0xFFFFFFF,0});//进栈一个特殊的数方便
	for(int i=1;i<=n;i++){
		cin>>temp.first;
		temp.second=i;
		while(s.top().first<=temp.first) s.pop();//保证栈内数据单调递减
		chafen[s.top().second]++;//差分,对栈顶那个元素的位置到现在这个元素的位置区间内都+1
		chafen[temp.second]--;
		s.push(temp);新数据压入栈
	}
	for(int i=1;i<=n;i++){//对差分数组前缀和,就是每个点的答案。
		chafen[i]+=chafen[i-1];
		cout<<chafen[i]<<" ";
	}
    return 0;
}

E - K-th Largest Connected Components

题目与数据范围:

思路:不用建图,并查集即可。给每个点都存它所在集合有哪些点。每次合并时,将两个集合合并,并将每个集合里有的点也合并,再进行排序。查询某个点的第k大点时,就找它父亲节点的集合内第k大的点,实际上就是该点的第k大点。因为k非常小,可以直接暴力维护。

复杂度O\left ( Q \right )

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int q,n;

int fa[200005];
int sett[200005][25];
int settnum[200005];//指针,表示这个集合中有几个元素

int find(int x){//并查集
    if(fa[x]!=x) return fa[x]=find(fa[x]);
    else return fa[x];
}


bool cmp(int a,int b){
    return a>b;
}

int query(int u,int k){//查询第k大
    int a=find(u);
    if(settnum[a]<k) return -1;
    else return sett[a][k];
}

void update(int u,int v){
    int a=find(u);
    int b=find(v);
    if(a==b) return ;
    else {//将两个集合合并
        fa[a]=b;
        for(int i=1;i<=settnum[a];i++) sett[b][++settnum[b]]=sett[a][i];//一个集合的元素合并到第二个集合
        sort(sett[b]+1,sett[b]+1+settnum[b],cmp);//排序
        if(settnum[b]>10) settnum[b]=10;//只保留前十个数字
        settnum[a]=0;
    }
    return ;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>q;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=n;i++) sett[i][1]=i,settnum[i]=1;
    while(q--){
        int opt;
        cin>>opt;
        if(opt==1){
            int a,b;
            cin>>a>>b;
            update(a,b);
        } else {
            int a,b;
            cin>>a>>b;
            cout<<query(a,b)<<endl;
        }
    }
    //for(int i=1;i<=n;i++) cout<<settnum[i]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值