一年一度的「幻影閣夏日品酒大會」隆重開幕了。大會包含品嚐和趣味挑戰 兩個環節,分別向優勝者頒發「首席品酒家」和「首席獵手」兩個獎項,吸引了眾多品酒師參加。
在大會的晚餐上,調酒師 rainbow 調製了 n 杯雞尾酒。這 n 杯雞尾酒排成一行,其中第 n 杯酒 (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 相似」的酒調兌可以得到的美味度的最大值。
思路:
很容易想到字尾陣列,然後就不會了。。。
考慮將height陣列從大到小排序,然後按順序每次將其兩邊的字尾集合合併在乙個集合內(用並查集即可,最開始所有字尾都在不同集合內)。
由於是按從大到小的順序排序的,若從這兩個集合內的分別任意選取兩個字尾,其lcp必等於h[i], 這兩個集合的合併對任意r<= h[i]的答案都有其大小乘積的貢獻。
最大值同樣維護即可,注意由於可能有負數,所以可以再維護乙個最小值。
**:
#include
#include
#include
#include
#define for(i,j,k) for(int i = j;i <= k;i++)
#define forr(i,j,k) for(int i = j;i >= k;i--)
const
int n = 300010;
using
namespace
std;
char s[n];
int sa[n], rank[n], h[n], t1[n], t2[n], c[n], n;
void buildsa(int m)
}bool cmp(int x, int y)
void buildheight()
for(i,1,n) c[i] = i;
sort(c + 1, c + n, cmp);
}int fa[n], sz[n], max[n], min[n];
long
long cnt[n], maxa[n];
int find(int x)
int main()
for(i,1,n-1)
forr(i,n-2,0)
cnt[i] += cnt[i+1], maxa[i] = max(maxa[i], maxa[i+1]);
for(i,0,n-1) printf("%lld %lld\n", cnt[i], cnt[i] ? maxa[i] : 0);
return
0;}
NOI2015 品酒大會(字尾樹 DP)
字尾自動機有乙個性質。就是如果倒建sam兩個串的lcp就是這兩個串的結束節點的lca。然後就可以愉快的跑dp了。對於每乙個字尾樹上的節點 u 它對 len u 的貢獻是 sum sum size v1 size v2 當然如果u就是乙個字尾的結尾就要加上自己。然後最大值怎麼辦?我們在每乙個節點上維護...
NOI2015 品酒大會 字尾自動機
建出sam和字尾樹 兩個子串的最長lcp就是他們的lca 因此我們只需求出最長的個數然後用字首和就能算出總個數,最大值也是同樣的方法,當然要逆序建sam才能保證他們的第一位相同。1 include 2 include 3 include 4 include 5 define ll long long...
Noi 2015 品酒大會
題目等價於求任意兩對字尾的lcp的值小於等於1,2 n的個數,以及權值乘積的最大值。求出字尾陣列的height值,然後預處理出每個height值能夠成為最小的區間。考慮每個height的值對答案的貢獻 如果height i 能夠成為最小的區間為 l,r 那麼個數便是 l i 1 r i 1 而乘積最...