ABC380
C
link
我们找到第
那么怎么找第
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
char s[500005];
int qr,dl,dr;
signed main(){
cin >> n >> k >> s+1;
int lx = 1,rx = 0,op = 0;
for(int i = 1;i <= n&&op <= k;++ i){
if(s[i] == '1'){
if(s[i-1] != '1') op++;
rx++;
if(op == k-1) qr = rx;
if(op == k) dl = lx,dr = rx;
}
else if(s[i] == '0'){
lx = i+1;
rx = i;
}
}
for(int i = 1;i <= n;++ i){
if(i == dl){
i = dr;
continue;
}
cout << s[i];
if(i == qr){
for(int j = dl;j <= dr;++ j)
cout << 1;
}
}
return 0;
}
D
link
找规律,发现找不出来规律。。。那么就开始分析吧。
我们可以发现,每次长度都会变成原来的两倍,那么如果我们对半砍,如果在一半的后面就给它对应到前一半的对应位置,记一次翻转,直到对应到
我们知道,这一个序列是同时变动的,所以我们可以把序列认为是一个字符,把
假设我们要找的位置时在四号三角形的那个序列里的,那么它一定三号三角形那个序列翻转后得到的,那么三号序列就是二号三角形那个序列翻转后得到的,直到第二个(一号)序列。这样是翻转了三次,加上它是第二个本来就翻转了一次,一共是四次,但是翻转四次和没翻转没有区别,所以就是原序列的那个位置,如果是奇数次翻转,那么就是原序列的那个位置转换一下大小写即可。
这时已经对上面的简洁的描述有了一定的理解,我们继续理解一下为什么是在一半的后面。如果是在五号序列的话,那么我们会直接到二号序列,在第二次对半砍的时候并不会有变化,那么如果我们仍然记了一次翻转,就会多翻转一次。
那么大部分需要理解的内容就结束了,那么怎么实现对半砍呢?我们可以发现每次对半砍完长度都是除以
那么我们现在解决了从多长开始砍,那么具体怎么砍呢?我们只要判断当前位置是否大于当前要砍的长度,如果不大于就行了,如果大于就减去这个长度,翻转次数加
最后判断一下翻转次数的奇偶性,翻一下即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
char s[200005];
int q,n;
int w[200005],cn;
char bian(int x){
if(x >= 'a'&&x <= 'z') return x-'a'+'A';
else return x-'A'+'a';
}
signed main(){
cin >> s+1 >> q;
n = strlen(s+1);
while(q--){
cn = 0;
int k;
cin >> k;
int g = (k+n-1)/n;
int gk = k%n;
if(gk == 0) gk = n;
int t = g,a = 1;
while(t){
w[++cn] = a;
t >>= 1;
a *= 2;
}
int c = 0;
for(int i = cn;i > 1;-- i){
if(g > w[i]){
g -= w[i],c++;
}
}
if(g == 2)c++;
c %= 2;
if(c == 1) cout << bian(s[gk]) << " ";
else cout << s[gk] << " ";
}
return 0;
}
E
link
一个我认为挺神奇的做法。
用并查集维护几个信息:
其他再记录几个信息:
那么初始化都是很好做的。
为了方便,我们使一个点的正确左右端点存储在它的终极祖先(也就是
对于操作
操作
首先,我们让
其次,我们把原来颜色的个数减少颜色块长度个,要改变到的颜色的个数加上颜色块长度个,把
然后我们判断一下这个颜色块和左右颜色是否变得相同了,如果颜色一样了,就合并到一起。
那么如何合并呢?首先,肯定要把一个的父亲赋成另一个,然后我们把那个在上面那个(终极祖先)的左右端点改变一下(左端点赋成两个左端点靠前的那个,右端点赋成两个右端点靠后的那个)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,q;
int f[500005];
int cnt[500005];
int col[500005];
int l[500005];
int r[500005];
int find(int x){
if(x == f[x]) return x;
else return f[x] = find(f[x]);
}
void merge(int x,int y){
x = find(x),y = find(y);
f[x] = y;
l[y] = min(l[y],l[x]);
r[y] = max(r[y],r[x]);
}
signed main(){
cin >> n >> q;
for(int i = 1;i <= n;++ i)
f[i] = col[i] = l[i] = r[i]= i,cnt[i] = 1;
while(q--){
int op;
cin >> op;
if(op == 1){
int x,c;
cin >> x >> c;
x = find(x);
cnt[c] += r[x]-l[x]+1;
cnt[col[x]] -= r[x]-l[x]+1;
col[x] = c;
if(l[x] > 1&&c == col[find(l[x]-1)])
merge(l[x]-1,x);
if(r[x] < n&&c == col[find(r[x]+1)])
merge(r[x]+1,x);
}
else{
int c;
cin >> c;
cout << cnt[c] << endl;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!