題目傳送門
題目大意:給出乙個字串,求出這個柿子的值:∑1≤
i
nlen
(ti)
+len
(tj)
−2×l
cp(t
i,tj
)\sum\limits_ 2
2(n−1)
×n×(
n+1)
。然後考慮後面如何求出任意兩個字尾的最長公共字首之和,把串反過來,就變成了求任意兩個字首的最長公共字尾。
建出sam,考慮每乙個狀態的貢獻,假設乙個狀態的 end
po
sendpos
endpos
集大小為 siz
e[i]
size[i]
size[i
],就說明其中任意乙個子串都恰好出現過 siz
e[i]
size[i]
size[i
] 次,對於任意乙個子串,假設他在 [a,
b]
[a,b]
[a,b
] 和 [c,
d]
[c,d]
[c,d
] 出現過,那麼以 b
bb 結尾和以 d
dd 結尾的字首的最長公共字尾至少會延伸到 a,c
a,ca,
c 這兩個位置,所以可以提供 1
11 的貢獻,至於在 a+1
a+1a+
1 和 c+1
c+1c+
1 位置的匹配,自然會有 [a+
1,b]
[a+1,b]
[a+1,b
] 和 [c+
1,d]
[c+1,d]
[c+1,d
] 兩個子串來提供貢獻 ,一共有 siz
e[i]
×(si
ze[i
]−1)
size[i]\times(size[i]-1)
size[i
]×(s
ize[
i]−1
) 種這樣的情況,所以貢獻就是 siz
e[i]
×(si
ze[i
−1])
size[i]\times (size[i-1])
size[i
]×(s
ize[
i−1]
)。而乙個狀態內有 len
(i)−
len(
link
(i))
len(i)-len(link(i))
len(i)
−len
(lin
k(i)
) 個子串,所以貢獻再乘上這個數量即可。
**如下:
#include
#include
#include
using
namespace std;
#define maxn 1000010
#define ll long long
int n;
char s[maxn]
;struct statest[maxn]
;int id=
0,last=
0,now,p,q;
int size[maxn]
;void
extend
(int x)
} last=now;
}int c[maxn]
,a[maxn]
;void
get_size()
intmain()
題解 AHOI2013 作業(莫隊)
有一段時間沒寫莫隊,今天wzb分享這道題,ssw02一看,我可以用莫隊水,寫的挺快的 歡迎 ssw02的部落格 給定長為n的序列 m個詢問,每次詢問在 下標在 l r 之間 數值在 a b 之間的數的種類和總數 n,m都是在1e5 的範圍內 可以離線,資料支援根號演算法,所以我們可以考慮分塊 總數和...
AHOI2013 找硬幣(搜尋)
time limit 10 sec memory limit 64 mb submit 348 solved 114 submit status 小蛇是金融部部長。最近她決定製造一系列新的貨幣。假設她要製造的貨幣的面值為x1,x2,x3 那麼x1必須為1,xb必須為xa的正整數倍 b a 例如1,5...
BZOJ3238 AHOI2013 差異 題解
參考 第一道接觸字尾樹的題,然而不想講這個東西。我們只需要知道將串倒著建字尾自動機parent樹就是字尾樹即可。然後兩個字尾的lcp就是他們的lca的len。設點u,則過點u的字尾就有su子樹的size和個,所以能配出size u size u 1 2個對,這條路徑的長度貢獻為 tr u l tr ...