字尾自動機有乙個性質。
就是如果倒建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 而乘積最...