ARC 077 SS(含嚴格證明) KMP

2021-08-22 10:15:07 字數 1475 閱讀 2972

結論題,假設那個串叫ss,並且操作一次後變成tt。

首先自己畫畫就會發現t比s多出來的那一段一定是s的乙個週期。(注意s的週期和ss的週期不是一回事,比如樣例)

字首技能:如果a和b都是s的週期,那麼(a, b)也是s的週期。因此s的最小正週期是s的任何乙個週期的週期,證明類似輾轉相除。

然後我們證明對於任意情況下,你選擇的週期,記做g,越小越好,也就是選擇最小週期g。否則,假設選擇的是h是s的乙個週期並且做出來的結果比g好。那麼根據一些border的知識我們知道因為g是最小正週期所以h的長度是g的長度我的若干倍,那麼顯然h能做到的事情g也能做到。因此h不會比g好。

否則,我們證明這麼兩件事情:

1)f(ss)=sgsg

這個其實自己畫畫就能畫出來。

2)若s的最小正週期是g,那麼串sg的最小正週期為:

a)g,如果g的長度是s的因數,這顯然。

b)s,else。我們證明b)。

反證。首先s是sg的乙個週期。因此假定h是sg的最小正週期,那麼|h|< |s|,否則結論成立。那麼根據border的知識,s的h的倍數。因此h也是s的乙個週期,從因此g的長度是h的長度的因數,因此g的長度是s的長度的因數,這樣就gg了。

我們考慮上述兩個結論在幹啥,根據1),我們知道就是,考慮這個偶串的前半段會不停的加上乙個最小正週期。

如果g的長度是s的長度的因數,那麼相當與每次在後面加入兩個g,也就是最終序列全是g,自己特判掉就可以了。下文假設g的長度不是s的長度的因數

根據後半段,我們假設操作了x次後這個串的前半部分是sg,s是操作第x-1次串,那麼s是sg的最小正週期,第x+1次操作後的串前半部分就是sgs,也就是每次操作得到的串都是上兩次操作得到的串拼起來,就像乙個斐數一樣。

實現的時候其實不用特判整除的情況。

#include

#include

#include

#include

#define n 200010

#define lint long long

#define debug(x) cerr<<#x<<"="<#define sp <<" "

#define ln namespace

std;

char s[n];int nxt[n];

struct e

inline e operator=(const e &e)

inline e operator+(const e &e)const

inline e operator-(const e &e)const

inline e operator+=(const e &e)

}a[1010];

inline

int getg(char *s,int n)

return n-nxt[n];

}inline e query(lint n,int c)

int main()

ARC077 D 組合數公式 水

題目大意 給你乙個長度為n 1的序列。1到n 1到n1到 n至少會出現一次。對於每個k,k 1,n k,k in 1,n k,k 1 n 問你有多少個本質不同的子串行。題目思路 一定有一對重複的。如 xayyyyyazzzz.那麼同時選擇x和z x和zx和 z區域裡的數,不選y yy區域,且選擇了中...