點此看題
首先轉化問題,我們可以求出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
logn)
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 的一種方式。乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比...