zoukankan      html  css  js  c++  java
  • CF 204 E

    CF 204 E

    两个做法。

    SAM+可持久化线段树合并+dp

    首先SAM上线段树合并的套路应该是比较常规的了,由于线段树是一个DAG,然后利用线段树上的边来dp。

    不过我还没写出来

    SA+单调栈

    可以发现每次包含的那k个在rank上一定是比较靠近的。

    /*
    {
    ######################
    #       Author       #
    #        Gary        #
    #        2021        #
    ######################
    */
    #include<bits/stdc++.h>
    #define rb(a,b,c) for(int a=b;a<=c;++a)
    #define rl(a,b,c) for(int a=b;a>=c;--a)
    #define LL long long
    #define IT iterator
    #define PB push_back
    #define II(a,b) make_pair(a,b)
    #define FIR first
    #define SEC second
    #define FREO freopen("check.out","w",stdout)
    #define rep(a,b) for(int a=0;a<b;++a)
    #define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
    #define random(a) rng()%a
    #define ALL(a) a.begin(),a.end()
    #define POB pop_back
    #define ff fflush(stdout)
    #define fastio ios::sync_with_stdio(false)
    #define check_min(a,b) a=min(a,b)
    #define check_max(a,b) a=max(a,b)
    using namespace std;
    //inline int read(){
    //    int x=0;
    //    char ch=getchar();
    //    while(ch<'0'||ch>'9'){
    //        ch=getchar();
    //    }
    //    while(ch>='0'&&ch<='9'){
    //        x=(x<<1)+(x<<3)+(ch^48);
    //        ch=getchar();
    //    }
    //    return x;
    //}
    const int INF=0x3f3f3f3f;
    typedef pair<int,int> mp;
    /*}
    */
    const int MAXLEN=2e5+10; 
    int lcp[MAXLEN],Rank[MAXLEN],sa[MAXLEN];
    mp mydate[MAXLEN];
    bool cmp(int A,int B){
    	return mydate[A]<mydate[B];
    }
    int cnt=0; 
    void SA(string s){
    	int len=s.length();
    	s='$'+s;
    	rb(i,1,len){
    		if(s[i]!='#')
    		Rank[i]=s[i];
    		else 
    		Rank[i]=INF+cnt,cnt++;
    	}
    	vector<int> order;
    	rb(i,1,len)
    		order.PB(i);
    	rb(j,0,18){
    		rb(i,1,len)
    			mydate[i]=II(Rank[i],i+(1<<j)<=len? Rank[i+(1<<j)]:-1);
    		sort(ALL(order),cmp);
    		rep(i,order.size())
    			Rank[order[i]]=(i==0? 1:Rank[order[i-1]]+(mydate[order[i]]!=mydate[order[i-1]]));
    	}
    	rb(i,1,len)
    		sa[Rank[i]]=i;
    }
    void LCP(string s){
    	int len=s.length();
    	s='$'+s;
    	s=s+'-';
    	int h=0;
    	rb(i,1,len){
    		if(Rank[i]==1){
    			lcp[i]=0;
    			continue;
    		}
    		int j=sa[Rank[i]-1];
    		if(h>0) h--;
    		while(s[j+h]!='#'&&s[i+h]!='#'&&s[j+h]==s[i+h]){
    			h++;
    		}
    		lcp[i]=h;
    	}
    }
    int lcprank[MAXLEN],is[MAXLEN];
    LL rest[MAXLEN];
    int coun[MAXLEN];
    int len[MAXLEN];
    int main(){
    	string ss;
    	int n,k;
    	scanf("%d%d",&n,&k);
    //	int haveh=0;
    	rb(i,1,n){
    		string si;
    		cin>>si;
    		len[i]=si.length();
    		ss+=si;
    		ss+='#';
    	}
    	if(k==1){
    		rb(i,1,n){
    			cout<<1ll*len[i]*(len[i]+1)/2<<' ';
    		}
    		return 0;
    	}
    	int len=ss.length();
    	SA(ss);
    	LCP(ss);
    	cnt=1;
    	rb(i,1,len){
    		lcprank[Rank[i]]=lcp[i];
    		if(ss[i-1]=='#'){
    			cnt++;
    			is[Rank[i]]=n+1;
    		}
    		else{
    			is[Rank[i]]=cnt;
    //			cout<<cnt<<endl;
    		}
    	}
    	vector<mp> v;
    	int have=0;
    	int r=0;
    	multiset<int> s;
    	rb(i,1,len){
    		coun[is[i-1]]--;
    		if(is[i-1]<=n&&is[i-1]>=1){
    			 have-=coun[is[i-1]]==0;
    		}
    		while(r<len&&have<k){
    			r++;
    			coun[is[r]]++;
    			if(is[r]<=n&&is[r]>=1&&coun[is[r]]==1) have++;
    		}
    		if(have<k) break;
    		v.PB(II(i,r));
    	}
    	vector<int> ret;
    	int lasl,lasr;
    	lasl=lasr=0;
    	for(auto it:v){
    		while(lasr<it.SEC){
    			lasr++;
    			s.insert(lcprank[lasr]);
    		}
    		while(lasl<=it.FIR){
    			if(lasl){
    				assert(s.find(lcprank[lasl])!=s.end());
    				s.erase(s.find(lcprank[lasl]));
    			}
    			lasl++;
    		}
    		ret.PB(*s.begin());
    	}
    	deque<mp> dq;
    	int best=-INF;
    	rb(i,1,len){
    		while(!dq.empty()&&dq.front().SEC<i){
    //			if(i==144) cout<<dq.front().FIR<<' '<<dq.front().SEC<<endl; 
    			check_max(best,dq.front().FIR);
    			dq.pop_front();
    		}
    		if(i<=v.size()){
    			while(!dq.empty()&&dq.back().FIR<=ret[i-1]){
    				dq.POB();
    			}
    			dq.PB(II(ret[i-1],v[i-1].SEC));
    		}
    		check_min(best,lcprank[i]);
    		if(!dq.empty()){
    			rest[is[i]]+=max(best,dq.front().FIR);
    		}
    		else{
    			rest[is[i]]+=max(0,best);
    		}
    	}
    	rb(i,1,n) printf("%lld ",rest[i]);
    	return 0;
    }
    
  • 相关阅读:
    CSS之旅——第二站 如何更深入的理解各种选择器
    CSS之旅——第一站 为什么要用CSS
    记录一些在用wcf的过程中走过的泥巴路 【第一篇】
    asp.net mvc 之旅—— 第二站 窥探Controller下的各种Result
    asp.net mvc 之旅—— 第一站 从简单的razor入手
    Sql Server之旅——终点站 nolock引发的三级事件的一些思考
    Sql Server之旅——第十四站 深入的探讨锁机制
    Sql Server之旅——第十三站 对锁的初步认识
    Sql Server之旅——第十二站 sqltext的参数化处理
    Sql Server之旅——第十一站 简单说说sqlserver的执行计划
  • 原文地址:https://www.cnblogs.com/gary-2005/p/14234783.html
Copyright © 2011-2022 走看看