• 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;
    }
    

      

  • 相关阅读:
    一篇文章看清楚JDK13的特性!
    【华为云技术分享】序列特征的处理方法之一:基于注意力机制方法
    【转载】PHP简单 对象(object) 与 数组(array) 的转换
    解决URL网址中遇到%2F或%5C(正反斜杠)等特殊符号导致URL重写失效出现404的问题
    hbuilder打包APP
    win7系统访问局域网中的wamp服务器
    hbuilder检测不到夜神模拟器 -- 解决办法
    hbuilder与夜神模拟器的链接
    webstorm(10.0.2)的端口号修改
    webstorm(10.0.2)设置测试服务器 -- 局域网内其他设备访问
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6401581.html
Copyright © 2020-2023  润新知