NOI2016 優秀的拆分

2021-10-03 09:11:43 字數 2245 閱讀 1535

點此看題

首先轉化問題,我們可以求出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設定乙個點,這樣乙個長為2×l

en2\times len

2×len的aaaa

aa串就會被相鄰的兩個點統計到,然後我們分情況討論:

第一種情況,lcp

+lcs

nlcp+lcslc

p+lc

sn(最長公共字首和最長公共字尾),這種情況一定不存在任何乙個長度為2×l

en2\times len

2×len的aaaa

aa串,因為如果存在的話lcp

lcplc

p應該更長。

第二種情況,lcp

+lcs

≥len

lcp+lcs\geq len

lcp+lc

s≥le

n,這樣的話aaaa

aa串是可以在深紅區域左右橫跳的,深紅段的長度就是中見紅綠相交的長度,可以通過差分算出a,b

a,ba,

b陣列。

至於l cp

lcplc

p和lc

slcs

lcs可以用字尾陣列+st

+st+s

t表o(1)

o(1)

o(1)

求出,還有一些細節,比如為了不算重,我們把lcs

lcslc

s從字首l−1

l-1l−

1和字首r−1

r-1r−

1來求,具體可以參考**。

由調和級數求和可知,時間複雜度o(n

log⁡n)

o(n\log n)

o(nlogn)

#include
#include

#include

using

namespace std;

#define ll long long

const

int m =

30005

;int

read()

int t,lg[m]

,a[m]

,b[m]

;ll ans;

struct suffix_array

}void

get_hi()

for(

int i=

1;i<=n;i++

) dp[i][0

]=hi[i]

;for

(int j=1;

(1<

<=n;j++

)for

(int i=

1;i+(1

<

<=n;i++

) dp[i]

[j]=

min(dp[i]

[j-1

],dp[i+(1

<<

(j-1))

][j-1]

);}int

ask(

int l,

int r)

}a,b;

intmain()

} ans=0;

for(

int i=

1;i<=n;i++

) a[i]

+=a[i-1]

,b[i]

+=b[i-1]

;for

(int i=

1;i) ans+

=a[i]

*b[i+1]

;printf

("%lld\n"

,ans);}

}

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 優秀的拆分

如果乙個字串可以被拆分為 aabb 的形式,其中 a 和 b 是任意非空字串,則我們稱該字串的這種拆分是優秀的。例如,對於字串 aabaabaa,如果令 a mathrm b mathrm 我們就找到了這個字串拆分成 aabb 的一種方式。乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比...