美團杯2020 半字首計數 字尾自動機

2021-10-06 06:29:30 字數 2392 閱讀 7475

題目大意:

蒜斜剛來pku的時候還不知道有「北大算協」這個社團,因此他總是覺得周圍的人在偷偷議論著他,比如說:

「算協(注:非蒜斜)舉辦的活動好有趣啊!」

「算協(注:非蒜斜)好帥啊!」

蒜斜每次聽到這些話就會想入非非,但仔細想想,自己好像也沒有那麼帥吧?最離譜的一次還是:

「算協(注:非蒜斜)有好多小哥哥」(霧)

自從蒜斜學習了半字首之後,他把這些話都看開了 —— 對他來說,只要這些話裡有 「蒜斜好」 的半字首就足夠了。

設小寫字母字串 s, 長度為 n, s[l:r] 表示第 l 個到第 r 個字元構成的子串, l>r 時對應空串。

定義半字首是 s[1:i]+s[j:k], 其中 0≤i給出字串 ss,你需要求出 ss 的所有半字首中,有多少個不同的字串。

輸入一行包含乙個小寫字串 s(1≤|s|≤106)。

輸出一行乙個整數,表示答案。

input

aab
output

6
explanation

字串aab的半字首有:空串,abaaabaab

input

pkusaamtcup
output

217
small task: |s|≤3000。

large task: |s|≤106。

時間限制:2s

空間限制:512mb

題目分析:讀完題後第一反應就是字尾自動機,但是需要猜結論或者變形,然後就止步於此了

首先因為題目規定的半字首是乙個字首與乙個子串拼接而成,對於每個半字首而言,肯定有很多的拼接方法,如果不加以約束的話,很容易重複統計,對於每個半字首 s[ 0 : i ] + s[ j : k ] 我們只計算 i 最大的那個半字首這樣就能做到不重不漏了

該如何確定某個半字首已經是 i 最大的呢,乙個必要條件是 s[ i + 1 ] != s[ j ] ,這個比較容易看出來,因為如果 s[ i + 1 ] == s[ j ] 的話,那麼顯然 s[ 0 : i + 1 ] + s[ j + 1 : k ] 是乙個比 i 更靠後的半字首,所以必要性成立

接下來證明一下充分性,假設有更靠後的乙個半字首 s[ 0 : i' ] + s[ j' : k' ] 滿足 i < i' ,因為 s[ 0 : i ] + s[ j : k ] == s[ 0 : i' ] + s[ j' : k' ] ,所以 s[ i + 1 : i' ] == s[ j : j + [一段區間] ] ,即 s[ i + 1 ] == s[ j ] ,與上面的結論相悖,所以證明了充分性

綜上,s[ i + 1 ] != s[ j ] 是 s[ 0 : i ] + s[ j : k ] 作為最後一次出現的半字首的重分必要條件

那麼接下來我們只需要列舉 i ,然後統計 s[ i + 1 : k ] 中有多少個首字母不為 s[ i + 1 ] 的本質不同子串即可

然後用字尾自動機解決就好了,因為要統計的區間實際上為 [ i + 1 , n ] ,所以我們可以倒著插入字串,因為字串在翻轉之後,本質不同的子串個數是不變的,每次插入後利用 last 指標更新 cnt 陣列,cnt[ j ] 表示截止到目前為止,首字母為 j 的本質不同子串有多少個,將答案累加就好了

最後需要注意的是,初始化為賦值為 n + 1 ,這裡的 1 是指空串,而 n 是指形如 [ 1 , 1 ] + 空串,[ 1 , 2 ] + 空串, [ 1 , 3 ] + 空串... +  [ 1 , n ] + 空串 ,這樣的半字首,因為字尾自動機無法統計空串的個數,所以需要我們自己手動計算上空串的貢獻

**:

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

typedef long long ll;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int n=1e6+100;

char s[n];

ll cnt[26];

int tot=1,last=1;

struct node

st[n<<1];

void add(int x)

}}int main()

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

return 0;

}

美團杯2020 半字首計數

題意 定義半字首是 s 1 i s j k s 1 i s j k s 1 i s j k 其中 0 i n s i len s j 1 k len s 0 i0 in s ilen s j 1 k len s 直觀上來說,你可以把半字首理解成某乙個字首 s 1 k 刪除掉某乙個子串後形成的結果 當...

美團杯2020 查查查樂樂(dp)

a.美團杯2020 查查查樂樂 查查查樂樂 是一段古老神秘的咒語,只有被選中的魔法師才有資格使用這一段咒語並享用它所帶來的力量 而如果這段咒語出現在了不具資格的魔法師的口中,這個魔法師將會遭到咒語的反噬並付出可怕的代價。這個學期,鎂團在一家魔法早教學校做兼職,他的任務是教小學生們魔法並幫助他們準備一...

美團2020筆試 字串的最長公共字首

題目描述 有最大長度十萬的多個字串。任意給兩個字串的編號,返回這兩個字串的最長公共字首長度。輸入 第1行輸入乙個整數n,代表字串數量,n最大為10000 第2 n 1行,每行乙個字串,字串長度最大為100000 第n 2行開始,每行輸入兩個整數a和b,代表需要計算公共字首的字串編號。輸出 返回a b...