zoukankan      html  css  js  c++  java
  • 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
    ",x.second,x.first);
    	else printf("%lld
    ",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;
    }
    
  • 相关阅读:
    7月的尾巴,你是XXX
    戏说Android view 工作流程《下》
    “燕子”
    Android开机动画bootanimation.zip
    戏说Android view 工作流程《上》
    ViewController里已连接的IBOutlet为什么会是nil
    My first App "Encrypt Wheel" is Ready to Download!
    iOS开发中角色Role所产生的悲剧(未完)
    UIScrollView实现不全屏分页的小技巧
    Apple misunderstood my app,now my app status changed to “In Review”
  • 原文地址:https://www.cnblogs.com/autoint/p/12336668.html
Copyright © 2011-2022 走看看