[NOI2015]品酒大會
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]品酒大會