比赛链接:bUNIQUE 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。
所以遍历初始字符串,统计一共出现几次。之后每次修改,判断对答案是否有影响,只需要看这个修改的点附近几个点的数据就可以。
复杂度
代码:
#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之间所有的数增加一个贡献。
复杂度
#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非常小,可以直接暴力维护。
复杂度
代码:
#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;
}