题解:CF2276E Good Substrings
forever516 · · 题解
线段树棒棒糖题。
题意
详见别人。
做法
考虑枚举左端点,考虑预处理对于一个端点,离他最近坏串端点为
显然如果
若
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define DF(i,a,b) for(int i=(a);i>=(b);i--)
const int N=3e5+10;
int T,n,nx[N][10];
struct SGT{
struct node{int v,k,d;}t[N<<2];
#define ls p<<1
#define rs p<<1|1
#define pp(p) t[p].v=t[ls].v+t[rs].v
void build(int p,int l,int r){
t[p]={0,0,0};
if(l==r)return;
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void pd(int p,int l,int r){
int&k=t[p].k,&d=t[p].d,mid=(l+r)>>1;
if(!k&&!d)return;
int ll=mid-l+1,lr=r-mid,kr=k+ll*d;
t[ls].v+=ll*k+ll*(ll-1)*d/2;
t[ls].k+=k,t[ls].d+=d;
t[rs].v+=lr*kr+lr*(lr-1)*d/2;
t[rs].k+=kr,t[rs].d+=d,k=d=0;
}
void update(int p,int l,int r,int ql,int qr,int k,int d){
if(qr<l||r<ql||ql>qr)return;
if(ql<=l&&r<=qr){
t[p].v+=(r-l+1)*(k+(l-ql)*d)+(r-l)*(r-l-1)*d/2;
t[p].k+=k+(l-ql)*d,t[p].d+=d;
return;
}
int mid=(l+r)>>1;pd(p,l,r);
if(ql<=mid)update(ls,l,mid,ql,qr,k,d);
if(qr>mid)update(rs,mid+1,r,ql,qr,k,d);
pp(p);
}
int query(int p,int l,int r,int pos){
if(l==r)return t[p].v;
int mid=(l+r)>>1;pd(p,l,r);
if(pos<=mid)return query(ls,l,mid,pos);
else return query(rs,mid+1,r,pos);
}
}t;
int get(int l,string s){
for(char c:s){
l=nx[l][c-'0'];
if(l==n+1)return l;
l++;
}
return l-1;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
F(j,0,9)F(i,1,n+1)nx[i][j]=n+1;
string s;cin>>s;s=" "+s;t.build(1,1,n);
DF(i,n,1){
nx[i][s[i]-'0']=i;
F(j,0,9)nx[i][j]=min(nx[i][j],nx[i+1][j]);
}
F(l,1,n){
int A=get(l,"2025"),B=get(l,"2026")-1;
if(B<A)continue;
t.update(1,1,n,l,A,B-A+1,0);t.update(1,1,n,A+1,B,B-A,-1);
}
F(i,1,n)cout<<((n-i+1)*i-t.query(1,1,n,i))<<" ";
cout<<"\n";
}
return 0;
}