NOI 2016 優秀的拆分 字尾陣列 差分

2022-03-25 23:30:54 字數 2680 閱讀 6653

題目大意:給你乙個字串,求所有子串的所有優秀拆分總和,優秀的拆分被定義為乙個字串可以被拆分成4個子串,形如$aabb$,其中$aa$相同,$bb$相同,$ab$也可以相同

作為一道國賽題,95分竟然就這麼給我們了!只是乙個$noip$難度的雜湊套$dp$啊......

95分就是從後往前找,統計$aa$串,每次統計一下從這個位置開始的所有子串 和 緊隨其後的等長串 相同的個數$sum$

$hash(i,i+j-1)==hash(i+j,i+2*j-1) sum[i]++$

然後再統計$bb$串,就是加上在這兩個串之後的位置的$sum$值,這樣就統計出了合法拆分數

$dp[i]+=sum[i+2*j]$

95分就這樣到手啦,竟然連自然溢位hash都不卡

1 #include 2 #include 3 #include 4 #include 5

#define ll long long

6#define ull unsigned long long

7#define n 2050

8#define seed 233

9#define idx(x) (x-'a'+1)

10using

namespace

std;

11//

re12

intt,len;

13char

str[n];

14int

dp[n],sum[n];

15ull hsh[n],sp[n];

16 ull ghsh(int x,int y)

17void

clr()

1824

intmain()

2544}45

}46int ans=0;47

for(int i=1;i<=len;i++)

48 ans+=sum[i];

49 printf("

%d\n

",ans);50}

51return0;

52 }

接下來才是本題的重點!$noi$豈是你想$ak$就$ak$的!出題人可能是想針對某位巨佬

不看題解這個正解思路真是很難想到......

思路大概是這樣的,其實我們每次只需要統計$aa$串的數量就行了,因為$aabb$串的數量等於,在$i-1$位結束的$aa$串的數量乘以在第$i$位開始的$aa$串的數量,用公式表示就是

接下來就是統計$st$和$ed$了,感覺正解的思路很神

先用字尾陣列+$st$表處理出任意兩個位置,作為字尾串開頭的$lcp$以及作為字首串末尾的$lcs$,求$lcs$可以把串反著讀再去套$sa$

每次選取乙個$a$串的長度$len$,再在原串每隔$len$的位置設乙個關鍵點

然後會發現乙個神奇的性質,任意乙個長度為$2*len$的串必然經過且僅經過2個關鍵點!

接下來統計經過所有長度為$2*len$所有$aa$串,比如選定兩個關鍵點$a,b$,且$a+len=b$

如果把$a$的和b$相同的字首和字尾拼在一起,且拼完之後長度》=len,說明存在至少乙個$aa$串

可以把$aa$串想象成乙個塊,在兩個關鍵點上移動,塊的左端點不能大於$a$,塊的右端點不能小於$b$,塊不能移動到上乙個或者下乙個關鍵點的位置,塊內必須是$aa$串,這樣,塊所有能移動的位置-塊的長度$len$,就是經過$ab$兩個關鍵點的所有$aa$串數

時間變成

,$logn$是調和級數的近似值

細節比較多需要仔細思考

1 #include 2 #include 3 #include 4 #include 5

#define ll long long

6#define n 30100

7#define seed 233

8#define idx(x) (x-'a'+1)

9using

namespace

std;

10//

re11

intt,len;

12int

lg[n];

13ll st[n],ed[n],s[n],e[n];

14struct

suffix

21void

get_suffix()

2239

for(i=1;i<=len;i++)

4046}47

void

get_st()

4855

int query(int x,int

y)56

58}p,s;

59void

clr()

6065

intmain()

6698}99

for(int i=1;i<=len;i++)

100 st[i]=st[i-1]+s[i],ed[i]=ed[i-1]+e[i];

101 ll ans=0

;102

for(int i=2;i<=len;i++)

103 ans+=ed[i-1]*st[i];

104 printf("

%lld\n

",ans);

105}

106return0;

107 }

NOI2016優秀的拆分 字尾陣列

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

NOI2016 優秀的拆分 字尾陣列

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

字尾陣列 NOI2016 優秀的拆分

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