QOJ#12181. abc
QOJ#12181. abc
题意
给你一个包含 \(\texttt{a,b,c}\) 的字符串。求所有区间的权值和。一个区间的权值定义为区间内出现次数的字母的个数,减去出现次数最少的字母的个数。(出现次数不为 \(0\))
\(n \le 2 \times 10^5\)。
思路
原式很难分讨。所以要先统一一下式子。
- 对于包含 \(3\) 种不同字母的区间 \([l,r]\):
\[val_{l,r} = \frac{|c_a-c_b| + |c_b-c_c| + |c_c-c_a|}2
\]
- 对于包含 \(2\) 种不同字母的区间 \([l,r]\),假设它包含 \(a,b\)。
\[val_{l,r} = |c_a-c_b|
\]
- 对于包含 \(1\) 种不同字母的区间 \([l,r]\),没有贡献。
这里怎么线性维护,感觉还是有点困难的。
这样要维护什么就很显然了吧。首先贡献乘二以去掉分母。
一种比较简洁的维护方法是,枚举两个字母 \(A,B\)。
- 对于包含 \(A,B\) 的区间,计算 \(2|c_A - c_B|\)。这恰好满足包含两种不同字母的区间的贡献。
- 对于包含三种字母的区间,要减去多余的贡献。计算 \(-|c_A - c_B|\)。
我们枚举区间右端点 \(r\)。
维护以 \(r\) 为右端点的区间的贡献。怎么从 \(r-1\) 转移过来。
加入 \(a_r\) 后,绝对值为 \(0,\pm1\) 的贡献需要变化。我们用 \(cnt_x\) 存差值(非绝对值)为 \(x\) 的区间个数。
因为不能左右移 \(cnt\) 数组。所以再记一个偏移量 \(tag\) 即可。
加入 \(a_r\) 后有可能要加入新的区间。直接加即可。
时间复杂度线性。
code
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace wing_heart {
constexpr int N=2e5+7;
int n;
char s[N];
int t[N];
int cnt[N<<1],tag;
ll ans;
void solve(int a,int b) {
memset(cnt,0,sizeof(cnt)); tag=0;
int cl=0,cr=0;
ll sl=0,sr=0;
int sa=0,sb=0;
int l=0;
rep(r,1,n) {
if(t[r]==a) cr+=cnt[-tag+N],sr+=cr,tag++,sl-=cl,cl-=cnt[-tag+N],sa++;
if(t[r]==b) cl+=cnt[-tag+N],sl+=cl,tag--,sr-=cr,cr-=cnt[-tag+N],sb++;
while(sa && sb) {
++l;
cnt[sa-sb-tag+N]++;
if(sa-sb>0) cr++, sr+=sa-sb;
if(sa-sb<0) cl++, sl+=sb-sa;
if(t[l]==a) --sa;
if(t[l]==b) --sb;
}
ans+=2*(sl+sr);
}
memset(cnt,0,sizeof(cnt)); tag=0;
cl=0,cr=0;
sl=0,sr=0;
sa=0,sb=0;
int sc=0,c=3^a^b;
l=0;
rep(r,1,n) {
if(t[r]==a) cr+=cnt[-tag+N],sr+=cr,tag++,sl-=cl,cl-=cnt[-tag+N],sa++;
if(t[r]==b) cl+=cnt[-tag+N],sl+=cl,tag--,sr-=cr,cr-=cnt[-tag+N],sb++;
if(t[r]==c) sc++;
while(sa && sb && sc) {
++l;
cnt[sa-sb-tag+N]++;
if(sa-sb>0) cr++, sr+=sa-sb;
if(sa-sb<0) cl++, sl+=sb-sa;
if(t[l]==a) --sa;
if(t[l]==b) --sb;
if(t[l]==c) --sc;
}
ans-=sl+sr;
}
}
void main() {
sf("%d",&n);
sf("%s",s+1);
rep(i,1,n) t[i] = s[i]-'a';
solve(0,1), solve(1,2), solve(2,0);
pf("%lld\n",ans/2);
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
wing_heart :: main();
}
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/19151871

浙公网安备 33010602011771号