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;
}

posted on 2020-02-20 17:43  autoint  阅读(272)  评论(0编辑  收藏  举报

导航