【CF1286F】 Fedya the Potter Strikes Back

题目

题意:对于一个字符串(S),对于某个子串(S[l,r]),如(S[l,r]=S[1,r-l+1]),那么就称该子串为好的;给定序列(w_i),定义一个子串(S[l,r])的权值为(min_{i=l}^r w_i)

初始时有一空串,每次在该串末位加入一个字符(c_i),求每次操作后字符串所有好的子串的权值和;强制在线。

(nleq 6 imes 10^5,w_i<2^{30})

不难发现这个好的子串其实就是( m border),这个动态加入我们只需要考虑答案的增量即可。

考虑从(i-1)加一个字符(c_i)之后( m border)的变化,如果(x)(S[1,i-1])是一个( m border),那么如果(S_{x+1}=c_i),那么(x+1)就是(S[1,i])( m border),反之则不是;特殊地,当(S_1=c_i)时,(1)会成为一个( m border)

我们发现这个变化比较简单,于是我们只需要考虑( m border)集合的变化即可。

加入新的( m border)特判一下即可;考虑如何删掉加入(c_i)后不合法的( m border),注意到(x)不合法当且仅当(S_{x+1} eq c_i),于是我们记(x)的颜色为(S_{x+1}),我们利用kmp构建一棵fali树,对于每一种颜色分别维护每个节点往上第一个该颜色的祖先;这样我们枚举(x)的颜色,从(i-1)暴力跳着删除即可;删除的时候贡献是一个区间( m min),对(w_i)动态构建一个st表即可;由于每个点只会被删除一次,所以复杂度是正确的。

之后对于合法的( m border),其只新增了一个(w_i),也就是贡献需要对(w_i)取一个(min),于是我们需要一个数据结构支持整体求和、将所有数和(w_i)(min)、插入以及删除,刚上来写了个权值线段树发现被卡空间了,真实自闭;其实只需要一个std::map暴力修改即可,由于一次插入的数之后被暴力取(min)一次,复杂度也是均摊正确的。

之后答案可能是(n^2 imes w_i)级别,于是可能会爆long long,所以统计答案的时候需要一个高精。

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=600001;const LL B=(1<<30)-1;
char c[5],S[maxn];
int A[105],C[105],ans26,ansB,ln;
int n,w[maxn],mn[20][maxn],nxt[maxn],fa[26][maxn],lm;
short col[maxn],lg[maxn];
inline void add(LL x) {
	ans26=(ans26+(x%26ll))%26;ansB=(ansB+(x&B))&B;
	ln=0;while(x)C[++ln]=x%10,x/=10ll;lm=max(lm,ln);
	for(re int i=1;i<=lm;i++)A[i]+=C[i],C[i]=0;
	for(re int i=1;i<=lm;i++)A[i+1]+=A[i]/10,A[i]%=10;
	while(A[lm+1]) A[lm+1]+=A[lm]/10,A[lm]%=10;++lm;
}
inline void write() {
	for(re int i=lm;i;--i)putchar(A[i]+'0');puts("");
}
inline int ask(int l,int r) {
	int k=lg[r-l+1];
	return min(mn[k][r],mn[k][l+(1<<k)-1]);
}
inline void add_St(int pos) {
	mn[0][pos]=w[pos];
	for(re int i=1;(1<<i)<=pos;i++) 
		mn[i][pos]=min(mn[i-1][pos],mn[i-1][pos-(1<<(i-1))]);
}
struct Data_Structure {
	typedef std::pair<int,int> pii;
	long long tot;std::map<int,int>ma;int st[maxn],top;
	std::map<int,int>::iterator it;
	inline void ins(int x,int v) {ma[x]+=v;tot+=1ll*x*v;}
	inline int qry(int x) {
		int sz=0;it=ma.upper_bound(x);
		for(;it!=ma.end();++it) {
			pii nw=*it;st[++top]=nw.first;
			tot-=1ll*nw.first*nw.second;sz+=nw.second;
		}
		while(top)ma.erase(st[top--]);return sz;
	}
}seg;
inline void jump(int co,int x,int pos) {
	while(x)seg.ins(ask(pos-x+1,pos),-1),x=fa[co][x];
}
int main() {
	n=read();lm=1;for(re int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(re int l=1;l<=n;l++) {
		scanf("%s",c);w[l]=read();
		c[0]=(c[0]-'a'+(int)(ans26%26))%26+'a';w[l]^=(ansB&B);
		add_St(l);S[l]=c[0];add(ask(1,l));
		if(l==1) {write();continue;}
		int p=nxt[l-1];
		while(p&&S[p+1]!=S[l])p=nxt[p];
		if(S[p+1]==S[l])nxt[l]=p+1;
		col[l-1]=c[0]-'a';
		for(re int i=0;i<26;++i)fa[i][l]=fa[i][nxt[l]];
		fa[col[nxt[l]]][l]=nxt[l];
		if(S[l]==S[1]) seg.ins(w[l],1);
		for(re int i=0;i<26;++i) {
			if(c[0]-'a'==i)continue;
			jump(i,fa[i][l-1],l-1);
		}
		seg.ins(w[l],seg.qry(w[l]));
		add(seg.tot);write();
	}
	return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/12261061.html