bzoj 4199 && NOI 2015 品酒大会

一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。

在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒。这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一。设 Str(l,r)Str(l,r) 表示第 ll 杯酒到第 rr 杯酒的 r−l+1r−l+1 个标签顺次连接构成的字符串。若 Str(p,po)=Str(q,qo)Str(p,po)=Str(q,qo),其中 1≤p≤po≤n1≤p≤po≤n,1≤q≤qo≤n1≤q≤qo≤n,p≠qp≠q,po−p+1=qo−q+1=rpo−p+1=qo−q+1=r,则称第 pp 杯酒与第 qq 杯酒是“rr相似” 的。当然两杯“rr相似” (r>1r>1)的酒同时也是“11 相似”、“22 相似”、……、“(r−1)(r−1) 相似”的。特别地,对于任意的 1≤p,q≤n1≤p,q≤n,p≠qp≠q,第 pp 杯酒和第 qq 杯酒都是“00相似”的。

在品尝环节上,品酒师 Freda 轻松地评定了每一杯酒的美味度,凭借其专业的水准和经验成功夺取了“首席品酒家”的称号,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 的美味度为 aiai。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 pp 杯酒与第 qq 杯酒调兑在一起,将得到一杯美味度为 apaqapaq 的酒。现在请各位品酒师分别对于 r=0,1,2,…,n−1r=0,1,2,…,n−1,统计出有多少种方法可以选出 22 杯“rr相似”的酒,并回答选择 22 杯“rr相似”的酒调兑可以得到的美味度的最大值。

输入格式

输入文件的第 11 行包含 11 个正整数 nn,表示鸡尾酒的杯数。

第 22 行包含一个长度为 nn 的字符串 SS,其中第 ii 个字符表示第 ii 杯酒的标签。

第 33 行包含 nn 个整数,相邻整数之间用单个空格隔开,其中第 ii 个整数表示第 ii 杯酒的美味度 aiai。

输出格式

输出文件包括 nn 行。第 ii 行输出 22 个整数,中间用单个空格隔开。第 11 个整数表示选出两杯“(i−1)(i−1)相似”的酒的方案数,第 22 个整数表示选出两杯“(i−1)(i−1)相似”的酒调兑可以得到的最大美味度。若不存在两杯“(i−1)(i−1)相似”的酒,这两个数均为 00。

 

 

我们从大往小枚举lcp,这样我们需要不停的合并一些区间并且查询一个位置所在区间的左右端点,并查集显然可以胜任。

用的st表,但预处理太慢在uoj上能过但在bzoj上会T掉,啊啊啊懒得卡常了。。。

     

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define ll long long
  6 #define inf 1LL<<62
  7 #define N 300005
  8 #define max(a,b) ((a)>(b)?(a):(b))
  9 #define min(a,b) ((a)<(b)?(a):(b))
 10 using namespace std;
 11 int read()
 12 {
 13     char c=getchar();int p=0,f=1;
 14     while(c<'0'||c>'9')
 15     {
 16         if(c=='-')f=-1;c=getchar();
 17     }
 18     while(c>='0'&&c<='9')p=p*10+c-'0',c=getchar();
 19     return p*f;
 20 }
 21 char s[N];
 22 int wb[N*2],rank[N*2],sa[N*2],sum[N];
 23 void da(int n,int m)
 24 {
 25     int *x=rank,*y=wb;
 26     for(int i=0;i<m;i++)sum[i]=0;
 27     for(int i=0;i<n;i++)sum[x[i]=s[i]]++;
 28     for(int i=1;i<m;i++)sum[i]+=sum[i-1];
 29     for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;
 30     int p=1;
 31     for(int j=1;p<n;j<<=1,m=p)
 32     {
 33         p=0;
 34         for(int i=n-j;i<n;i++)y[p++]=i;
 35         for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
 36         for(int i=0;i<m;i++)sum[i]=0;
 37         for(int i=0;i<n;i++)sum[x[i]]++;
 38         for(int i=1;i<m;i++)sum[i]+=sum[i-1];
 39         for(int i=n-1;i>=0;i--)sa[--sum[x[y[i]]]]=y[i];
 40         swap(x,y);x[sa[0]]=0;p=1;
 41         for(int i=1;i<n;i++)
 42          x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
 43     }
 44     return ;
 45 }
 46 int h[N];
 47 void cal(int n)
 48 {
 49     for(int i=1;i<=n;i++)rank[sa[i]]=i;
 50     int k=0;
 51     for(int i=0;i<n;i++)
 52     {
 53         if(k)k--;
 54         int j=sa[rank[i]-1];
 55         while(s[i+k]==s[j+k])k++;
 56         h[rank[i]]=k;
 57     }
 58     return ;
 59 }
 60 ll ans[N][2];
 61 int n;
 62 int v[N];
 63 int f[N],g[N];
 64 int findf(int x)
 65 {
 66     if(f[x]==x)return x;
 67     return f[x]=findf(f[x]);
 68 }
 69 int findg(int x)
 70 {
 71     if(g[x]==x)return x;
 72     return g[x]=findg(g[x]);
 73 }
 74 struct node
 75 {
 76     int pos,zhi;
 77     friend bool operator < (node aa,node bb)
 78     {
 79         return aa.zhi>bb.zhi;
 80     }
 81 }q[N];
 82 ll mn[N*2][25];// 22
 83 ll mx[N*2][25];// 22
 84 int lg[N*2];
 85 void st()
 86 {
 87     int now=0;
 88     for(int i=1;i<=n;i*=2)
 89     {
 90         for(int j=i;j<i<<1;j++)
 91         {
 92             lg[j]=now;
 93         }
 94         now++;
 95     }
 96     for(int i=1;i<=n;i++)mn[i][0]=v[sa[i]],mx[i][0]=v[sa[i]];
 97     for(int i=1;i<=22;i++)
 98     {
 99         for(int j=1;j<=n;j++)
100         {
101             if(j+(1<<(i-1))<=n)mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
102             else mx[j][i]=mx[j][i-1];
103             if(j+(1<<(i-1))<=n)mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
104             else mn[j][i]=mn[j][i-1];
105         }
106     }
107 }
108 ll qurmx(int l,int r)
109 {
110     int k=lg[r-l+1];
111     return max(mx[l][k],mx[r-(1<<k)+1][k]);
112 }
113 ll qurmn(int l,int r)
114 {
115     int k=lg[r-l+1];
116     return min(mn[l][k],mn[r-(1<<k)+1][k]);
117 }
118 int main()
119 {
120     n=read();
121     scanf("%s",s);
122     ll mx1=-inf,mx2=-inf;
123     ll mn1=inf,mn2=inf;
124     for(int i=0;i<n;i++)
125     {
126         v[i]=read();
127         if(v[i]>mx1)mx2=mx1,mx1=v[i];
128         else if(v[i]>mx2)mx2=v[i];
129         if(v[i]<mn1)mn2=mn1,mn1=v[i];
130         else if(v[i]<mn2)mn2=v[i];
131     }
132     da(n+1,256);
133     cal(n);st();
134     for(int i=1;i<=n;i++)q[i].pos=i,q[i].zhi=h[i];
135     for(int i=0;i<=n;i++)ans[i][1]=-inf;
136     sort(q+1,q+n+1);
137     for(int i=1;i<=n+1;i++)f[i]=i,g[i]=i;
138     for(int i=1;i<=n;i++)
139     {
140         if(q[i].zhi==0)break;
141         int t=q[i].pos;
142         int aa=findf(t-1);int bb=findg(t+1);
143         ll q1=t-aa;ll q2=bb-t-1;
144         ans[q[i].zhi][0]+=q1*(q2+1);
145         f[t]=aa;g[t]=bb;
146         ans[q[i].zhi][1]=max(ans[q[i].zhi][1],qurmx(aa,t-1)*qurmx(t,bb-1));
147         ans[q[i].zhi][1]=max(ans[q[i].zhi][1],qurmn(aa,t-1)*qurmn(t,bb-1));
148 
149     }
150     for(int i=n-1;i>=1;i--)ans[i][0]+=ans[i+1][0],ans[i][1]=max(ans[i][1],ans[i+1][1]);
151     ans[0][0]=(ll)n*((ll)n-1)/2;
152     ans[0][1]=max(mx1*mx2,mn1*mn2);
153     for(int i=0;i<=n-1;i++)
154     {
155         if(ans[i][0])printf("%lld %lld\n",ans[i][0],ans[i][1]);
156         else puts("0 0");
157     }
158     return 0;
159 }

 

posted @ 2017-01-13 09:23  SD_le  阅读(314)  评论(0编辑  收藏  举报
重置按钮