NOI2015 品酒大會(字尾樹 DP)

2022-05-19 20:40:32 字數 1211 閱讀 3789

字尾自動機有乙個性質。

就是如果倒建sam兩個串的lcp就是這兩個串的結束節點的lca。

然後就可以愉快的跑dp了。

對於每乙個字尾樹上的節點\(u\),它對\(len[u]\)的貢獻是\(\sum_\sum_}size[v1]*size[v2]\)當然如果u就是乙個字尾的結尾就要加上自己。

然後最大值怎麼辦?我們在每乙個節點上維護最小次小,最大次大然後dp轉移就行。

因為這題\(k\)相似就是\(k-1\)相似。最後還要對個數求個和,對最大值求乙個\(max\)

#include#include#include#include#includeusing namespace std;

#define int long long

const int n=601000;

const int inf=1e18+10;

int cnt,head[n];

int tot=1,u=1,trans[n][27],size[n],len[n],fa[n];

int mx[n],mxx[n],mn[n],mnn[n],dp[n];

int ans[n],anss[n],n,a[n];

char s[n];

struct edgee[n];

void add(int u,int v)

int read()

while(ch>='0'||ch<='9')

return sum*f;

}void ins(int id,int c)

} u=x;

}void dfs(int u)

else if(mx[v]>mxx[u])mxx[u]=mx[v];

if(mn[v]=1;i--)ins(i,s[i]-'a'+1);

for(int i=1;i<=tot;i++)add(fa[i],i);

for(int i=0;i<=n+1;i++)anss[i]=-inf;

dfs(1);

for(int i=n;i>=0;i--)ans[i]+=ans[i+1],anss[i]=max(anss[i],anss[i+1]);

for(int i=0;iif(ans[i]==0)printf("0 0\n");

else printf("%lld %lld\n",ans[i],anss[i]);

return 0;

}

NOI 2015 品酒大會 字尾陣列

一年一度的 幻影閣夏日品酒大會 隆重開幕了。大會包含品嚐和趣味挑戰 兩個環節,分別向優勝者頒發 首席品酒家 和 首席獵手 兩個獎項,吸引了眾多品酒師參加。在大會的晚餐上,調酒師 rainbow 調製了 n 杯雞尾酒。這 n 杯雞尾酒排成一行,其中第 n 杯酒 1 i n 被貼上了乙個標籤si,每個標...

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 而乘積最...