专栏文章
题解:AT_abc418_d [ABC418D] XNOR Operation
AT_abc418_d题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio9mt0x
- 此快照首次捕获于
- 2025/12/02 15:37 3 个月前
- 此快照最后确认于
- 2025/12/02 15:37 3 个月前
AT_abc418_d [ABC418D] XNOR Operation题解
简略题目描述
有一个只包含的字符串,要求出可以通过(类似异或)的方式能令序列变为的子串个数。
数据范围
- 是整数。
- 是长度为 的、仅由
0和1组成的字符串。
通过观察可知,判断一个子串为美丽字符串和 的数量是没有关系的。 因为所有的 都可以通过操作变成 个 ,而发现如果 的数量为偶数的话,可以通过一定数量的操作使得序列变成只有 的序列,但是如果 的数量为奇数的话,无论怎么合并,都会剩下一个单独的 无法合并。
于是问题转换为了求连续区间内 的个数为偶数的数量。而我们可以用前缀和来解决一个区间内的 的个数,再用区间长度减去当以 为左端点,且区间 的数量为奇数的区间个数即可。
于是就可以省去枚举 的循环了。
时间复杂度:
空间复杂度:
代码细节详见注释。
code(码风丑陋,请见谅(无坑,放心食用))
:
CPP#include <bits/stdc++.h>
using namespace std;
#define int long long
const int nn=2e5+5;
int n,s[nn],ji[nn][2],la[nn],v,e,ans;
string t;
//s[i]表示1-i的0的个数
//la[i]表示离i最近的0的位置(包括i)
//ji[i][0]=1表示当前有偶数个0
//ji[i][1]=1表示当前有奇数个0
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>t;
t=" "+t;
for(int i=1;i<=n;i++){
s[i]=s[i-1];
if(t[i]=='0'){
v++;
e^=1;
s[i]++,la[i]=i;
}else{
la[i]=la[i-1];
}
ji[i][e]=1;//差分
}
for(int i=1;i<=n;i++)ji[i][0]+=ji[i-1][0],ji[i][1]+=ji[i-1][1];//前缀和
int v=s[n];
for(int i=1;i<=n;i++){
if(s[i-1]%2==1){//当前出现了奇数个0
ans+=(n-i+1);
ans-=(ji[n][0]-ji[i-1][0]);//前缀和
}else {//当前出现了偶数个0
ans+=(n-i+1);
ans-=(ji[n][1]-ji[i-1][1]);//前缀和
}
}
cout<<ans;
return 0;
}
蒟蒻赛时调了30min,导致题差 写出(TAT)。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...