CF1286F Fedya the Potter Strikes Back
Fedya the Potter Strikes Back
给定一个字符串 S 和权值数组 W
定义 S 的一个子串是好的,当且仅当这个子串等于 S 的某个前缀
一个子串 S[L : R] 的权值是 W[L...R] 的最小值
对于 S 的每个前缀,求他的所有好的子串的权值之和
N ≤ 105
题解
https://www.cnblogs.com/asuldb/p/12261061.html
不难发现这个好的子串其实就是border,这个动态加入我们只需要考虑答案的增量即可。
考虑从i−1加一个字符ci之后border的变化,如果x在S[1,i−1]是一个border,那么如果Sx+1=ci,那么x+1就是S[1,i]的border,反之则不是;特殊地,当S1=ci时,1会成为一个border。
我们发现这个变化比较简单,于是我们只需要考虑border集合的变化即可。
加入新的border特判一下即可;考虑如何删掉加入ci后不合法的border,注意到x不合法当且仅当Sx+1≠ci,于是我们记x的颜色为Sx+1,我们利用kmp构建一棵fail树,对于每一种颜色分别维护每个节点往上第一个该颜色的祖先;这样我们枚举x的颜色,从i−1暴力跳着删除即可;删除的时候贡献是一个区间min,对wi动态构建一个st表即可;由于每个点只会被删除一次,所以复杂度是正确的。
之后对于合法的border,其只新增了一个wi,也就是贡献需要对wi取一个min,于是我们需要一个数据结构支持整体求和、将所有数和wi取min、插入以及删除。只需要一个std::map暴力修改即可。由于一次插入的数之后被最多被暴力取min一次,复杂度是均摊正确的。
之后答案可能是n2×wi级别,于是可能会爆long long
,所以统计答案的时候需要一个高精。Codeforces不支持__int128
(大概它是32位电脑),所以只好手写pair<long long,long long>
。
CO int N=6e5+10;
char s[N];int w[N];
namespace ST{ // sparse table
int lg[N],mn[N][20];
void init(int n){
for(int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
}
void insert(int p,int v){
mn[p][0]=v;
for(int i=1;i<=lg[p];++i)
mn[p][i]=min(mn[p][i-1],mn[p-(1<<(i-1))][i-1]);
}
int query(int l,int r){
int k=lg[r-l+1];
return min(mn[r][k],mn[l+(1<<k)-1][k]);
}
}
namespace BT{ // balanced tree
map<int,int> cnt;
int64 sum;
void insert(int v,int c){
cnt[v]+=c;
sum+=(int64)v*c;
}
int query(int v){ // >v
int siz=0;
vector<int> del;
for(map<int,int>::iterator i=cnt.upper_bound(v);i!=cnt.end();++i){
siz+=i->second;
del.push_back(i->first);
sum-=(int64)i->first*i->second;
}
for(int x:del) cnt.erase(x);
return siz;
}
}
int nxt[N],col[N],fa[N][26];
CO int64 mod=1e18;
IN int operator%(CO pair<int64,int64>&x,int y){
return (x.first%y+(x.second%y)*(mod%y))%y;
}
IN pair<int64,int64>&operator+=(pair<int64,int64>&x,int64 y){
x.first+=y,x.second+=x.first/mod,x.first%=mod;
return x;
}
IN void writeln(CO pair<int64,int64> x){
if(x.second) printf("%lld%018lld\n",x.second,x.first);
else printf("%lld\n",x.first);
}
int main(){
int n=read<int>();
ST::init(n);
pair<int64,int64> ans={0,0};
for(int i=1;i<=n;++i){
scanf("%s",s+i),read(w[i]);
s[i]=(s[i]-'a'+ans%26)%26+'a',w[i]^=ans%(1<<30);
ST::insert(i,w[i]);
ans+=ST::query(1,i);
if(i==1){
writeln(ans);
continue;
}
int j=nxt[i-1];
while(j and s[j+1]!=s[i]) j=nxt[j];
nxt[i]=j+(s[j+1]==s[i]);
col[i-1]=s[i]-'a';
copy(fa[nxt[i]],fa[nxt[i]]+26,fa[i]);
fa[i][col[nxt[i]]]=nxt[i];
if(s[1]==s[i]) BT::insert(w[i],1);
for(int c=0;c<26;++c)if(c!=s[i]-'a')
for(int j=fa[i-1][c];j;j=fa[j][c])
BT::insert(ST::query(i-j,i-1),-1);
BT::insert(w[i],BT::query(w[i]));
ans+=BT::sum;
writeln(ans);
}
return 0;
}