3 27模擬賽 sutoringu 字尾陣列

2022-04-02 14:22:49 字數 2138 閱讀 5665

\(\color\)

(應本人要求刪掉惹)

upd on 21.4.3

找到有人把它又出出來的題了:

哦這就是2019多校題,但估計也不是原創:

**是nirobc 18年出的oi考試題

給你\(n,k\)和長為\(n\)的字串\(s\)。乙個區間\([l,r]\)是合法的,當且僅當\(s[l...r]\)能被分成\(k\)個相同的子串。求有多少個合法區間。

\(n,k\leq3\times10^5\)。

列舉單個子串的長度\(len\),在\(s\)上從\(1\)開始每隔\(len\)個位置放乙個關鍵點,分成若干塊。

考慮相鄰\(k\)個關鍵點,以它們開頭的\(k\)個子串是否相同。如果它們兩兩之間的\(lcp\)都\(\geq len\),顯然是合法的。考慮怎麼求這\(k\)個位置的\(lcp\)。

建\(sa\),\(lcp\)是兩兩\(rk\)之間的最小值,也就是區間\([\min\,\max\]\)之間的最小值。用\(set\)動態維護一下,查詢\(lcp\)就是\(o(1)\)的了。

需要列舉\(o(n\log n)\)次,這樣這部分複雜度是\(o(n\log^2n)\)。

還有左右端點在塊內的情況,也就是跨過了\(k-1\)個整塊。容易發現這\(k-1\)塊的子串一定需要是相同的。同樣用\(sa\)和\(set\)先判一下。

設左端點\(l\)在第\(p\)塊內,右端點\(r\)在\(p+k\)塊內。記\(l[p],r[p]\)分別為第\(p\)塊的左右端點,可以發現合法的\(l\)範圍是字首\(r[p]\)與\(r[p+1]\)的最長公共字尾,可以反著建個\(sa\)求出來,設為\(a\)。同理合法\(r\)的範圍是字尾\(l[p+k]\)與\(l[p+k-1]\)的最長公共字首,設為\(b\)(注意與\(len-1\)取\(\min\))。

\(r\)的長度需要在\([len-a,len-1]\)之間,所以此時合法的區間個數就是\(b-len+a+1\)。

複雜度也是\(o(n\log^2n)\)。

ps:

不知道標算是啥...(好像是sam+主席樹)這是\(\color}\color}\)的做法。

這個其實和優秀的拆分差不多...但是考場都忘了啊=-=

#include #include #include #include #include #define rg register

#define rev(x) (n-(x)+1)

//#define gc() getchar()

#define maxin 500000

#define gc() (ss==tt&&(tt=(ss=in)+fread(in,1,maxin,stdin),ss==tt)?eof:*ss++)

typedef long long ll;

const int n=3e5+5;

int s[n],log[n];

char in[maxin],*ss=in,*tt=in;

struct suffix_array

for(int i=1; i<=n; ++i) rk[sa[i]]=i;

ht[1]=0;

for(int i=1,k=0; i<=n; ++i)

for(int i=1; i<=n; ++i) mn[0][i]=ht[i];

for(int j=1; j<=log[n]; ++j)

for(int t=1<>1]+1;

sa1.build(s,n), std::reverse(s+1,s+1+n), sa2.build(s,n);

ll ans=0;

for(int len=1; len*k<=n; ++len)

if(len==1) continue;

std::setst2;

for(int t=k-1,i=len+1; t--; i+=len) st2.insert(sa1.rk[i]);

for(int i=k*len+1,j=len; i<=n; i+=len,j+=len)

st2.erase(sa1.rk[j+1]), st2.insert(sa1.rk[i]);

} }printf("%lld\n",ans);

return 0;

}

《省賽模擬賽補》

c題 比賽的時候已經想到了統計最底層的每個序列的出現次數,但是一開始想的是建圖之後dfs處理,但是發現很難處理出來。其實正確的思路是拓撲排序去處理次數。我們在最後建圖完成之後,倒著從n回去拓撲即可。但是這裡有個坑點,就是一開始統計入度可能是不正確的。例如 3 1 2 4 1 2 3是1,2的父節點,...

日常模擬賽

none 100 100 10 210 不太會做.好像.是個sb題.嗯.div3t1難度 include include define int long long define gc getchar define pc putchar inline int read void print int x...

模擬賽記錄

模擬賽記錄 8.20 7 30 9 30 數學入門難度6道題 300分 8.21 7 40 9 50 圖論 普及 6道題 500分 8.22 學長模擬賽 7 40 10 00 提高 300 分 80 分 8.23 圖論 普及 提高 8 40 11 30 300分 180分 8.24 字串 入門難度 ...