Distinct Substrings(擴展KMP)

Distinct Substrings

寫完這題發現自己曾經的擴展KMP板子(ZZ函數)太laji了!現在的板子簡潔又漂亮,並且這題很妙!

題意

給定一個長爲nn的數字串,問在尾部獨立的添加11~mm這些數字分別會使原串增加多少本質不同的子串

思路

  1. 看到本質不同,首先想到了後綴自動機,每次在結尾插入元素後只需要知道插入元素的父節點是誰,然後利用len[np]len[fa[np]]len[np]-len[fa[np]]就可以知道增加了多少新的本質不同的子串
  2. 但就本題而言,有如下三點會否定這個做法:
    1. 空間32M32M,而後綴自動機要開很多的1e61e6的數組
    2. 數組元素是數字,而不是字符,因此假設用mapmap存邊,空間會爆炸!
    3. 多組數據+O(nlogn)O(nlogn)+大常數在兩秒內顯然是跑不出來的
  3. 否定後綴自動機後,我們仍然可以利用這個求新增子串的思想;在後綴自動機中,思考一個節點的fatherfather節點是什麼?答案是與當前節點endposendpos不同的最長的後綴,因此我們如果能夠在不建立後綴自動機的情況下找到這個最長的後綴,那不就好了?
  4. 而正好,ZZ algorithmalgorithm剛好有一種經典的做法,考慮將原字符串翻轉,就可以將求最長的後綴變成了求最長的前綴。並且要考慮分別添加mm個不同數字的情況下的子串增量,我們可以O(n)O(n)的計算貢獻,見如下式子:
    best[s[i]]=max(best[s[i]],1+z[i+1])best[s[i]]=max(best[s[i]],1+z[i+1])
    其中best[p]best[p]表示在翻轉後的串的前面增加pp這個字符會有多少重複的子串出現,則n+1best[p]n+1-best[p]就表示新增的本質不同的子串數量。這個maxmax旨在尋找最長的前綴
  5. 最後,此問題可以在O(Tn)O(T*n)的複雜度下解決,並且空間複雜度也完全OKOK(不過這題數據好像有些問題,導致暴力O(n2)(O(n^2))zz數組也能過。。。)
#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}

const int maxn = 1e6+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;

int n, m;
int s[maxn], z[maxn], best[maxn];

int main() {
    //ios::sync_with_stdio(false); cin.tie(0);
    while(cin>>n>>m) {
        for(int i=1; i<=n; ++i) scanf("%d", &s[i]);
        reverse(s+1,s+1+n);
        for(int i=2, j=1; i<=n; ++i) {
            if(i<j+z[j]) z[i]=min(j+z[j]-i,z[i-j+1]);
            while(i+z[i]<=n&&s[i+z[i]]==s[z[i]+1]) z[i]++;
            if(i+z[i]>j+z[j]) j=i;
        }
        for(int i=1; i<=n; ++i) best[s[i]]=max(best[s[i]],1+z[i+1]);
        ll ans=0, three=1;
        for(int i=1; i<=m; ++i) {
            three=three*3%mod;
            ans^=three*(n+1-best[i])%mod;
        }
        cout<<ans<<endl;
        for(int i=1; i<=max(n,m); ++i) best[i]=z[i]=0;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章