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 }