\(\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 字串 入門難度 ...