sa首先將t和si首尾相接連起來,每兩個串之間隔乙個未出現過的字元,求出字尾陣列及height陣列,即字尾陣列中相鄰兩個字尾的最長公共字首。然後o(n)掃瞄可得每個字尾i和在原t串中開始的每個字尾j最長的最長公共字首是多少,記為near[i],這樣字尾j即在字尾陣列中與字尾i最近的兩個在t中開始的字尾中的乙個。即。這樣我們就可以求出在sp中每個位置sp,q向後匹配最長near[i]長度能使在這段長度內任意的以sp,q開始的串都能在t中找到對應的子串。
現在我們已經滿足了在t串中有相應子串的條件,還需要滿足一定的奇偶性。用乙個四位的二進位制表示四種鹼基的奇偶性。對於每個si,我們做如下統計:用乙個0~15的陣列f表示從st到en區間內每種奇偶性出現了多少次。從前向後掃瞄,移動st和en使對於每個i有st=i及en=i+near[i]-1,注意到st和en只會向後移動,對於每個i可用16的時間掃面陣列統計滿足要求的。en=en+1時,是將原來統計到的所有以en-1結尾的串轉變為以en結尾,每個被統計到的串都在尾部加上了鹼基en,記是從陣列f轉移到f』, f』[i]=f[ix],表示異或,x表示鹼基en本身奇偶性,即x是乙個二的冪。此外還要f』[x]=f』[x]+1,即新增了乙個僅由en構成的串。st=st+1時,刪除了乙個從st一直到en的最長的串,直接在對應位置減一即可。
綜上,我們用o(nlog2n)的時間構建字尾陣列,再用o(16n)的時間掃瞄。你也可以用dc3把字尾陣列寫成o(n)的。這裡的n指的是所有字串的總長度。
sam可是出題人說本來不想讓上面的演算法過的,應該用字尾自動機。對t建字尾自動機,然後用每個si在字尾自動機上匹配,即可輕鬆地求出near。後面的掃瞄同上。這個演算法把構建字尾陣列的o(nlog2n)優化為o(4n),而且這裡的n不再是所有字串的總長度而是t的長度,速度會略有提公升。
#include
#define ll long long
using
namespace std;
const
int n=
2e5+
77,s=
1<<4;
int n,m,q;
char s[n]
,t[n]
,id[
128]
,yjy[4]
;namespace sam
sam[
(n <<1)
+5];
int las=
1,tot=1;
inline
void
ins(
int x)
} las=p;}}
int l,cnt[s+5]
,cur,tag;
ll ans;
intmain()
for(
;l < i - len+1;
++l)
--cnt[cur ^ tag]
,cur ^=1
<< id[s[l]];
tag ^=1
<< x,cur ^=1
<< x,
++cnt[tag ^(1
<< x)];
for(
int i0=
0;i0 <2;
++i0)
if(yjy[0]
==-1|| yjy[0]
== i0)
for(
int i1=
0;i1 <2;
++i1)
if(yjy[1]
==-1|| yjy[1]
== i1)
for(
int i2=
0;i2 <2;
++i2)
if(yjy[2]
==-1|| yjy[2]
== i2)
for(
int i3=
0;i3 <2;
++i3)
if(yjy[3]
==-1|| yjy[3]
== i3)
ans +
= cnt[
(i0 |
(i1 <<1)
|(i2 <<2)
|(i3 <<3)
)^ tag];}
printf
("%lld\n"
,ans);}
}
物件導向部分 201
小夥伴們,還在為不知道怎麼下手而頭疼嗎,我們程式競賽協會來幫你們啦 啦啦啦。另外,如果有對程式設計含有濃厚興趣的同學,我們隨時歡迎你們的加入喲 策劃 譚兆飛 程式設計 管懷文 協助 一號人員要求給她打碼 乾脆二號也打碼好了o o 其實只是提供了題目啦 物件導向部分 201 include inclu...
2 01揹包問題
有 nn 件物品和乙個容量是 vv 的揹包。每件物品只能使用一次。第 ii 件物品的體積是 vivi,價值是 wiwi。求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。輸出最大價值。輸入格式 第一行兩個整數,n,vn,v,用空格隔開,分別表示物品數量和揹包容積。接下來有 n...
2 01揹包問題
有 nn 件物品和乙個容量是 vv 的揹包。每件物品只能使用一次。第 ii 件物品的體積是 vivi,價值是 wiwi。求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。輸出最大價值。第一行兩個整數,n,vn,v,用空格隔開,分別表示物品數量和揹包容積。接下來有 nn 行,每...