【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\),求每次操作后字符串所有好的子串的权值和;强制在线。

\(n\leq 6\times 10^5,w_i<2^{30}\)

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

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

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

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

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

之后答案可能是\(n^2\times 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;
}
posted @ 2020-02-04 20:45  asuldb  阅读(368)  评论(0编辑  收藏  举报