BZOJ4560 NOI2016 優秀的拆分

2022-05-07 20:12:09 字數 1619 閱讀 6846

bzoj

洛谷考慮乙個形如\(aabb\)的串是由兩個形如\(aa\)的串拼起來的

那麼我們設

\(f[i]\):以位置\(i\)為結尾的形如\(aa\)串的個數

\(g[i]\):以位置\(i\)為開頭的形如\(aa\)串的個數

\[\therefore ans=\sum_^nf[i]*g[i+1]

\]題目的難點轉化為求\(f,g\)。

但是,其實我們只要\(o(n^2)\)暴力求一下就有\(95pts\)了,

所以我們接下來考慮最後的\(5pts\)怎麼拿:

我們列舉\(a\)的長度\(len\)

將所有位置為\(len\)的倍數的點設為關鍵點,

則如果乙個\(aa\)滿足要求

這個\(aa\)必過兩個關鍵點,

那麼我們要算的就是相鄰兩個關鍵點對答案的貢獻:

記相鄰兩個關鍵點為\(,i,j\)那麼\(j=i+len\)

記\(lcp=lcp(suf(i), suf(j)),lcs=lcs(pre(i-1),pre(j-1))\)

那麼,如果\(lcp+lcs,則不能構成\(aa\)

為什麼呢?

相當於這樣一種情況:

\[\underbrace_\;\overbrace_\;....\underbrace_}^\;\underbrace_

\]這樣子是不合法的。

反之,中間兩段的\(lcp,lcs\)會有交,而我們這個\(a\)串的終點落在中間長度為\(lcp+lcs-len+1\)的交上都是可以的

因為這樣的話平移一下可以保證緊跟著出現乙個不重疊的\(a\)串

又因為串\(a\)起點和終點分別出現的位置是一段區間,所以直接分別在\(f,g\)上差分即可

複雜度是調和級數\(o(nlogn)\)。

具體細節看**:

#include #include #include #include #include #include #include using namespace std; 

inline int gi()

const int max_n = 3e4 + 5;

char a[max_n];

int n, lg[max_n], f[max_n], g[max_n];

struct suffixarray

for (int i = 1; i <= n; i++) rnk[sa[i]] = i;

for (int i = 1, j = 0; i <= n; i++)

} int st[16][max_n];

void buildst()

int query(int l, int r)

} a, b;

void sol()

} } for (int i = 1; i <= n; i++) f[i] += f[i - 1], g[i] += g[i - 1];

long long ans = 0;

for (int i = 1; i < n; i++) ans += 1ll * f[i] * g[i + 1];

printf("%lld\n", ans);

} int main ()

bzoj 4650 Noi2016 優秀的拆分

原來只會兩個log平衡樹合併。後來圍觀claris在uoj群上秒題後會了這道題。列舉a b 的長度l,然後列舉i kl,考慮字首i,i l和字尾i 1,i l 1,求出字首的lcp和字尾的lcp,然後合法的方案就在乙個方案內。差分一下即可。注意要避免重複。ac 如下 include include ...

BZOJ 4650 Noi2016 優秀的拆分

題解 求解每個位置向左向右aa串的個數f x g x 列舉a的長度,每a個位置設乙個關鍵點 每乙個a一定僅且跨越乙個關鍵點 然後求出相鄰關鍵點向前向後的最長公共字首的長度,這會對一段區間的f,g產生影響 用差分 字首和統計答案 include include include includeusing...

BZOJ4650 Noi2016 優秀的拆分

設 f i 表示以 i 結尾的square個數,g i 表示以 i 開頭的square個數,則 ans sum f ig 列舉square中長度的一半 l 每 l 步取乙個關鍵點,那麼每個該長度的square的肯定恰好經過兩個相鄰的關鍵點,且位置差距為 l 的字元一一匹配。所以相鄰關鍵點之間通過字尾...