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;
    }
    
  • 相关阅读:
    如何设置java环境变量
    创建DLL动态链接库——模块定义法(def)
    创建DLL动态链接库——声明导出法
    fwrite()中参数含义——size和count经常用搞反
    解决VS2010中winsock.h与winsock2.h冲突(重复定义)——转载
    组播协议——IGMP v2报文头介绍
    IP/IGMP/UDP校验和算法
    POJ1625 Censored!
    HDU2222(Keywords Search,AC自动机)
    POJ1204 Word Puzzle(AC自动机)
  • 原文地址:https://www.cnblogs.com/autoint/p/12336668.html
Copyright © 2011-2022 走看看