NOI2016 優秀的拆分

2022-05-20 08:17:36 字數 1305 閱讀 1325

如果乙個字串可以被拆分為\(aabb\)的形式,其中\(a\)和\(b\)是任意非空字串,則這種拆分方式是優秀的。給出乙個長度為\(n(n\le30000)\)的字串\(s\),求其子串所有拆分方式中優秀拆分的總個數。

若用\(f[i]\)表示以\(i\)結尾的可以表示為\(aa\)形式的字尾數,用\(g[i]\)表示以\(i\)開頭的可以表示為\(aa\)形式的字首數。則答案為\(\sum_^f[i]\times g[i+1]\)。這樣我們就把原問題轉化為只需要考慮前/字尾為\(aa\)形式的問題。

列舉\(a\)的長度\(l\),每隔\(l\)設定乙個關鍵點\(p\)。對於一對相鄰的關鍵點\(p_i\)和\(p_\),我們求\(l_1=\min(\operatorname(p_i,p_),l)\)和\(l_2=\min(\operatorname(p_i,p_i+1),l)\)。若\(l_1+l_2-1\ge l\),則存在這樣的\(aa\),我們可以算出所有合法位置,\(f\)和\(g\)區間\(+1\),可以使用差分維護。

\(\operatorname\)和\(\operatorname\)可以用雜湊+二分實現,列舉\(l\)的時間複雜度是調和級數\(\mathcal o(n\log n)\)。總時間複雜度\(\mathcal o(n\log^2n)\)。

#include#include#include#includetypedef long long int64;

inline int getint()

const int n=30001;

const int base=31,mod=998244353;

char s[n+1];

int n,hash[n],pwr[n],f[n],g[n];

inline int idx(const char &ch)

inline int calc(const int &l,const int &r)

inline int lcs(const int &p1,const int &p2,const int &lim) else

} return l-1;

}inline int lcp(const int &p1,const int &p2,const int &lim) else

} return l-1;

}int main()

}} for(register int i=1;i<=n;i++)

int64 ans=0;

for(register int i=1;iprintf("%lld\n",ans);

} return 0;

}

NOI2016 優秀的拆分

看到題目,資料範圍有點怪異。對於95 的資料,對於100 的資料,意思是只有5分是正解。好吧,95pts的 很明顯,答案就是 而如何才能拿到100pts呢?我們可以先列舉a段的長度,很明顯每個長度為lcp,與往後求lcs,若 這樣就可以通過 include include include inclu...

NOI2016 優秀的拆分

題目實際上要求我們求從每個點出發的aa串的數量 考慮點i的答案,發現如果字首i與字首j j i 的最長公共字尾 i j,那麼i點出發向前就存在乙個長度為i j的aa串,題目即求對於每個字首,有多少個在他之前的字首滿足條件 考慮字尾自動機,由於每個字首都是字尾自動機parent樹上的一點,即兩個字首的...

NOI2016 優秀的拆分

點此看題 首先轉化問題,我們可以求出a i b i a i b i a i b i 即以i ii結束 開始的aaaa aa串的數量,這樣答案就可以表示為 a i b i 1 sum a i times b i 1 a i b i 1 求這兩個陣列,可以隔距離len lenle n設定乙個點,這樣乙個...