CF1555D Say No to Palindromes(线段树)
CF1555D Say No to Palindromes
看题目问法是线段树来做的。
仔细分一下发现,若有一个没有回文子串的串 \(s\),对于任意 \(i\),一定有 \(s_i\neq s_{i-1}\neq s_{i+1}\)。也就是说吗,这三个字符分别对应 a,b,c
。也就是说, \(s\) 的形式只有一下 \(6\) 种:
abcabc...
bcabca...
cabcab...
acbacb...
cbacba...
bacbac...
对于线段树一个区间,我们维护 \(s_{l,r}\) 对应 \(6\) 种可能修改后的形式修改的字符数量即可。
明显我们可以通过这 \(6\) 的两完成 pushup
。
其他操作和基础线段树差不多。
为了写代码方便,你需要对着 \(6\) 种形式合理编号。
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
using namespace std;
int read() {
char ch=getchar();
while(ch<'a'||ch>'c') {
ch=getchar();
}
return (ch-'a'+1)%3;
}
const int MAXN=2e5+10;
int n,m;
int a[MAXN];
struct segment {
int val[2][3],len;
}s[MAXN<<2];
segment pushup(segment lft,segment rgt) {
segment ret;
ret.len=lft.len+rgt.len;
for(int j=0;j<2;j++) {
for(int i=0;i<3;i++) {
ret.val[j][i]=lft.val[j][i]+rgt.val[j][(i+lft.len%3)%3];
}
}
return ret;
}
void build(int l,int r,int p) {
if(l==r) {
for(int j=0;j<2;j++) {
for(int i=0;i<3;i++) {
s[p].val[j][i]=1;
}
}
if(a[l]==1) {
s[p].val[0][0]=s[p].val[1][0]=0;
}
if(a[l]==2) {
s[p].val[0][1]=s[p].val[1][2]=0;
}
if(a[l]==0) {
s[p].val[0][2]=s[p].val[1][1]=0;
}
s[p].len=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
s[p]=pushup(s[p<<1],s[p<<1|1]);
}
segment query(int l,int r,int p,int x,int y) {
if(r<x||y<l) {
return s[0];
}
if(x<=l&&r<=y) {
return s[p];
}
int mid=(l+r)>>1;
return pushup(query(l,mid,p<<1,x,y),query(mid+1,r,p<<1|1,x,y));
}
signed main() {
cin>>n>>m;
for(int i=1;i<=n;i++) {
a[i]=read();
}
build(1,n,1);
while(m--) {
int l,r;
scanf("%d%d",&l,&r);
segment tmp=query(1,n,1,l,r);
int ans=1e9;
for(int j=0;j<2;j++) {
for(int i=0;i<3;i++) {
ans=min(ans,tmp.val[j][i]);
}
}
printf("%d\n",ans);
}
return 0;
}
看了一眼官方题解后发现这个题是傻题。
希望大家学习一下这个思路就行,以官方题解的解法为主。