1. 程式人生 > >[NOI2015]品酒大會

[NOI2015]品酒大會

挑戰 clu class red printf sort 選擇 stdin char

Description

一年一度的“幻影閣夏日品酒大會”隆重開幕了。大會包含品嘗和趣味挑戰兩個環節,分別向優勝者頒發“首席品酒家”和“首席獵手”兩個獎項,吸引了眾多品酒師參加。
在大會的晚餐上,調酒師 Rainbow 調制了 n 杯雞尾酒。這 n 杯雞尾酒排成一行,其中第i杯酒(1≤i≤n)被貼上了一個標簽 si,每個標簽都是 26 個小寫英文字母之一。設Str(l,r)表示第 l 杯酒到第 r 杯酒的r?l+1個標簽順次連接構成的字符串。若 Str(p,po)=Str(q,qo),其中1≤p≤po≤n,1≤q≤qo≤n,p≠q,po?p+1=qo?q+1=r,則稱第 p 杯酒與第 q 杯酒是“r相似” 的。當然兩杯“r相似”(r>1)的酒同時也是“1 相似”、“2 相似”、…、“(r?1) 相似”的。特別地,對於任意的 1≤p,q≤n,p≠q,第 p 杯酒和第 q杯酒都是“0相似”的。
在品嘗環節上,品酒師 Freda 輕松地評定了每一杯酒的美味度,憑借其專業的水準和經驗成功奪取了“首席品酒家”的稱號,其中第 i 杯酒 (1≤i≤n)的美味度為 ai。
現在 Rainbow 公布了挑戰環節的問題:本次大會調制的雞尾酒有一個特點,如果把第 p 杯酒與第 q 杯酒調兌在一起,將得到一杯美味度為 ap?aq 的酒。現在請各位品酒師分別對於 r=0,1,2,…,n?1,統計出有多少種方法可以選出 2 杯“r相似”的酒,並回答選擇 2 杯“r相似”的酒調兌可以得到的美味度的最大值。

Input

輸入文件的第 1 行包含 1 個正整數 n,表示雞尾酒的杯數。
第 2 行包含一個長度為 n 的字符串 S,其中第 i 個字符表示第 i 杯酒的標簽。
第 3 行包含 n 個整數,相鄰整數之間用單個空格隔開,其中第 i 個整數表示第 i 杯酒的美味度 ai。

Output

輸出文件包括 n 行。
第 i 行輸出 2 個整數,中間用單個空格隔開。第 1 個整數表示選出兩杯“(i?1)相似”的酒的方案數,第 2 個整數表示選出兩杯“(i?1)相似”的酒調兌可以得到的最大美味度。
若不存在兩杯“(i?1)相似”的酒,這兩個數均為 0。

Sample Input

樣例1:
10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7

樣例2:
12
abaabaabaaba
1 -2 3 -4 5 -6 7 -8 9 -10 11 -12

Sample Output

樣例1:
45 56
10 56
3 32
0 0
0 0
0 0
0 0
0 0
0 0
0 0

樣例2:
66 120
34 120
15 55
12 40
9 27
7 16
5 7
3 -4
2 -4
1 -4
0 0
0 0

Hint

樣例1提示:
用二元組 (p,q) 表示第 p 杯酒與第 q 杯酒。
0 相似:所有 45 對二元組都是 0 相似的,美味度最大的是 8×7=56。
1 相似:(1,8) (2,4) (2,9) (4,9) (5,6) (5,7) (5,10) (6,7) (6,10) (7,10),最大的 8×7=56。
2 相似:(1,8) (4,9) (5,6),最大的 4×8=32。
沒有 3,4,5,…,9 相似的兩杯酒,故均輸出 0。

更多數據下載

技術分享

題解: 問題轉化為分別求LCP>=r的後綴的組數 算是道思維題吧,關鍵需要明白lcp為L的一組 對後面的L-1 L-2 L-3....也可以貢獻 那麽就出現了正解,要不然就只能 n^2logn亂搞了 顯然 按上面得出的結論 可以從大到小排序high數組,然後分別處理,一組lcp為L的後綴顯然和大於L後綴匹配 所以合並答案直接相乘即可,合並可以並查集亂搞
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 const int N=300005;const ll INF=2e18;
 9 char S[N];int n,c[N],x[N],y[N],s[N],a[N],sa[N],rk[N],high[N];
10 bool comp(int i,int j,int k){return y[i]==y[j] && y[i+k]==y[j+k];}
11 void Getsa(){
12     int m=29,t=0;
13     for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
14     for(int i=1;i<=m;i++)c[i]+=c[i-1];
15     for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
16     for(int k=1;k<=n;k<<=1){
17         t=0;
18         for(int i=n-k+1;i<=n;i++)y[++t]=i;
19         for(int i=1;i<=n;i++)if(sa[i]>k)y[++t]=sa[i]-k;
20         for(int i=0;i<=m;i++)c[i]=0;
21         for(int i=1;i<=n;i++)c[x[i]]++;
22         for(int i=1;i<=m;i++)c[i]+=c[i-1];
23         for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i];
24         swap(x,y);
25         x[sa[1]]=t=1;
26         for(int i=2;i<=n;i++)x[sa[i]]=comp(sa[i-1],sa[i],k)?t:++t;
27         if(t==n)break;
28         m=t;
29     }
30 }
31 void Getheight(){
32     for(int i=1;i<=n;i++)rk[sa[i]]=i;
33     int j,h=0;
34     for(int i=1;i<=n;i++){
35         j=sa[rk[i]-1];
36         if(h)h--;
37         for(;j+h<=n && i+h<=n;h++)if(s[i+h]!=s[j+h])break;
38         high[rk[i]-1]=h;
39     }
40 }
41 ll mx[N],mn[N],ans[N],size[N],mul[N];int r[N],fa[N];
42 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
43 bool comper(int i,int j){return high[i]>high[j];}
44 void Getanswer(){
45     for(int i=1;i<=n;i++)r[i]=fa[i]=i,size[i]=1,mx[rk[i]]=mn[rk[i]]=a[i],mul[i]=-INF;
46     sort(r+1,r+n+1,comper);
47     int x,y,tmp;
48     for(int i=1;i<=n;i++){
49         x=find(r[i]);y=find(r[i]+1);tmp=high[r[i]];
50         ans[tmp]+=size[x]*size[y];
51         mul[tmp]=max(max(mn[x]*mn[y],mx[x]*mx[y]),mul[tmp]);
52         mn[x]=min(mn[x],mn[y]);
53         mx[x]=max(mx[x],mx[y]);
54         size[x]+=size[y];fa[y]=x;
55     }
56     for(int i=n-1;i>=0;i--)ans[i]+=ans[i+1],mul[i]=max(mul[i],mul[i+1]);
57     for(int i=0;i<n;i++)printf("%lld %lld\n",ans[i],ans[i]?mul[i]:0);
58 }
59 int main()
60 {
61     freopen("savour.in","r",stdin);
62     freopen("savour.out","w",stdout);
63     scanf("%d",&n);
64     scanf("%s",S+1);
65     for(int i=1;i<=n;i++)s[i]=S[i]-a+1;
66     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
67     Getsa();Getheight();Getanswer();
68     return 0;
69 }

[NOI2015]品酒大會