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;
    }
    
  • 相关阅读:
    jQuery使用工具集
    JQuery解决鼠标单双击冲突问题
    线程池
    配置文件application.properties参数详解
    SpringBoot整合SpringDataJPA
    获取数据库的自增主键(六)
    【使用篇二】邮箱自动化配置集成(18)
    Quartz自动化配置集成
    Cron表达式详解
    标准盒模型和怪异盒模型的区别
  • 原文地址:https://www.cnblogs.com/gary-2005/p/14234783.html
Copyright © 2011-2022 走看看