zoukankan      html  css  js  c++  java
  • BZOJ4199/UOJ131 [Noi2015]品酒大会

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:UOJ131

     

    正解:后缀数组

    解题报告:

      考虑两杯酒如果r相似,显然也会r-1相似、r-2相似…

      那么我肯定是从大往小做,大的做完了的贡献可以直接合并进小的。

      我们先构出后缀数组,得到height数组。

      把height数组排个序,可以得到最大的height,那么超过这个最大的显然无解。  

      那么我每次把两个相邻的部分所在的集合合并,合并时计算一下对于当前集合的贡献,ans就是两个max或者min乘起来,cnt就是两个cnt相乘。

      就做完了,板子题做起来还是挺simple的…

     

    //It is made by ljh2000
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <complex>
    using namespace std;
    typedef long long LL;
    const int MAXN = 300011;
    const LL inf = (1LL<<62);
    int n,rank[MAXN],sa[MAXN],wa[MAXN],wb[MAXN],c[MAXN],height[MAXN];
    char ch[MAXN];
    int father[MAXN],w[MAXN];
    LL ans[MAXN],cnt[MAXN],size[MAXN],maxl[MAXN],minl[MAXN];
    
    struct node{ int h,id; }a[MAXN];
    inline bool cmp(node q,node qq){ return q.h>qq.h; }
    inline int find(int x){ if(father[x]!=x) father[x]=find(father[x]); return father[x]; }
    
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void build(int m){
    	int *x=wa,*y=wb;
    	for(int i=1;i<=m;i++) c[i]=0;
    	for(int i=1;i<=n;i++) c[x[i]=(ch[i]-'a'+1)]++;
    	for(int i=2;i<=m;i++) c[i]+=c[i-1];
    	for(int i=1;i<=n;i++) sa[c[x[i]]--]=i;
    	for(int k=1,p;k<=n;k<<=1) {
    		p=0; for(int i=n-k+1;i<=n;i++) y[++p]=i;
    		for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
    		for(int i=1;i<=m;i++) c[i]=0;
    		for(int i=1;i<=n;i++) c[x[y[i]]]++;
    		for(int i=2;i<=m;i++) c[i]+=c[i-1];
    		for(int i=n;i>=1;i--)/*!!!*/ sa[c[x[y[i]]]--]=y[i];//!!!
    		swap(x,y); p=1; x[sa[1]]=1;
    		for(int i=2;i<=n;i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p:++p;
    		m=p; if(p==n) break;
    	}
    }
    
    inline void calc_height(){
    	int i=1,j,k=0; for(int i=1;i<=n;i++) rank[sa[i]]=i;
    	for(;i<=n;height[rank[i++]]=k/*!!!*/) 
    		for(k?k--:0 ,j=sa[rank[i]-1];ch[i+k]==ch[j+k];k++) ;
    }
    
    inline void work(){
    	n=getint(); scanf("%s",ch+1); for(int i=1;i<=n;i++) w[i]=getint();
    	build(256); calc_height(); for(int i=1;i<=n;i++) ans[i]=-inf;
    	for(int i=2;i<=n;i++) a[i-1].h=height[i],a[i-1].id=i/*!!!*/;
    	sort(a+1,a+n,cmp); int now=1,r1,r2,x,y;
    	for(int i=1;i<=n;i++) size[i]=1,father[i]=i,maxl[rank[i]]=minl[rank[i]]=w[i];
    	for(int h=a[1].h;h>=0;h--) {
    		ans[h]=ans[h+1]; cnt[h]=cnt[h+1];
    		for(;now<n && a[now].h==h;now++) {
    			x=a[now].id; y=x-1;
    			r1=find(x); r2=find(y);
    			ans[h]=max(ans[h],max(maxl[r1]*maxl[r2],minl[r1]*minl[r2]));
    			cnt[h]+=size[r1]*size[r2];
    
    			maxl[r2]=max(maxl[r2],maxl[r1]);
    			minl[r2]=min(minl[r2],minl[r1]);
    			size[r2]+=size[r1];
    			father[r1]=r2;
    		}
    	}
    	for(int i=0;i<n;i++) if(cnt[i]!=0) printf("%lld %lld
    ",cnt[i],ans[i]); else printf("0 0
    ");
    }
    
    int main()
    {
        work();
        return 0;
    }
    

      

  • 相关阅读:
    JDBC 复习4 批量执行SQL
    JDBC 复习3 存取Oracle大数据 clob blob
    Oracle复习
    Linux命令(1)grep
    JDBC 复习2 存取mysql 大数据
    JDBC 复习1 DBUtil
    php 环境搭建问题
    Windows 批处理 bat 开启 WiFi 菜单选项 设置ID PWD
    Bat 批处理启动和停止Oracle 服务
    docker 学习1 WSL docker ,Windows docker
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6401581.html
Copyright © 2011-2022 走看看