3 条题解

  • 1
    @ 2026-8-2 9:04:29

    一眼恶心kmp。 例题和题解详见:https://blog.csdn.net/tenkuo/article/details/152000561

    本题题解注释代码:

    #include<bits/stdc++.h> 
    using namespace std;
     
    typedef long long LL;
    const int N = 5e5 + 10; 
    char s[N];    
    LL z[N];          // z: s 的 Z 函数数组
    int len;
     
    // 计算文本串 s 的 Z 函数
    // z[i] 表示 s[i..lenb]与 s[1..lenb] 的最长公共前缀长度(LCP) 
    void get_z() {
    	memset(z, 0, sizeof(z)); 
        z[1] = len;  // 特殊情况:s[1..lenb]与自身的 LCP 就是整个字符串长度
        
        // 初始化最右匹配区间 [l, r]
        // 这区间就是 s[l..r] = s[1..r - l + 1]
        // l、r: 当前已知最右匹配区间的左端点和右端点
        for (int i = 2, l = 0, r = 0; i <= len; i ++) {
        	// i 从 2 开始,代表后缀开始的位置,l = r = 0,一开始并没有区间 
            // 如果 i 在当前最右匹配区间 [l, r] 内
            if (i <= r) {
                z[i] = min(z[i - l + 1], 1ll * (r - i + 1));
                // 根据定义 1 到 r - l + 1 和 l 到 r 是相等的
    			// 所以 i - l + 1 到 r - l + 1 和 i 到 r 是相等的
    			// 因此以 i - l + 1 为标准,最大 LCP 最多就可以取 r - i + 1
    			// 但是如果这个 r - i + 1 比 z[i - l + 1] 还要大的话,那当然取不了
    			// 反之 r - i + 1 比 z[i - l + 1] 小,那也不能取大的
    			// 因为只有 i - l + 1 到 r - l + 1 是相等的 
            }
            
            // 从 z[i] 开始尝试扩展匹配
            // 检查 s[1 + z[i]] 和 s[i + z[i]] 是否相等
            while (1 + z[i] <= len && i + z[i] <= len && s[1 + z[i]] == s[i + z[i]]) {
                z[i] ++;     // 匹配成功,LCP 长度 + 1
            }
            
            // 如果匹配后右边界超过当前最右匹配区间,则更新区间
            if (i + z[i] - 1 > r) {
                l = i;                // 新区间的左端点
                r = i + z[i] - 1;     // 新区间的右端点
            }
        }
    }
     
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	
    	cin >> (s + 1);
        len = strlen(s + 1);
        
        get_z();
    
        for (int i = 1; i <= len; i ++) {
            cout << z[i] << " ";
        }
        cout << "\n";
        
        return 0;
    }
    
    
    
    • 0
      @ 2026-8-9 10:51:45

      SA秒了

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int mxn=5e5+10;
      int n,m,p,sa[mxn],rk[mxn],oldrk[mxn],height[mxn],cnt[mxn],id[mxn],st[mxn][25],lg2[mxn];
      int get(int l,int r){
      	if(l==r)return n-sa[l]+1;
      	if(l>r)swap(l,r);
      	r--;
      	int d=lg2[r-l+1];
      	return min(st[l][d],st[r-(1<<d)+1][d]);
      }
      int main(){
      	ios::sync_with_stdio(0);
      	cin.tie(0);
      	string s;
      	cin>>s;
      	n=s.size();
      	for(int i=2;i<=n;i++)lg2[i]=lg2[i>>1]+1;
      	s=" "+s;
      	m=255;
      	for(int i=1;i<=n;i++)cnt[rk[i]=s[i]]++;
      	for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
      	for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;
      	for(int w=1;p<n;w<<=1,m=p){
      		int cur=0;
      		for(int i=n-w+1;i<=n;i++)id[++cur]=i;
      		for(int i=1;i<=n;i++)if(sa[i]>w)id[++cur]=sa[i]-w;
      		for(int i=1;i<=m;i++)cnt[i]=0;
      		for(int i=1;i<=n;i++)cnt[rk[i]]++;
      		for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
      		for(int i=n;i;i--)sa[cnt[rk[id[i]]]--]=id[i];
      		memcpy(oldrk,rk,sizeof(rk));
      		p=0;
      		for(int i=1;i<=n;i++){
      			if(oldrk[sa[i]]==oldrk[sa[i-1]]&&oldrk[sa[i]+w]==oldrk[sa[i-1]+w])rk[sa[i]]=p;
      			else rk[sa[i]]=++p;
      		}
      	}
      	for(int i=1,k=0;i<=n;i++){
      		if(rk[i]==n)continue;
      		if(k)k--;
      		while(s[i+k]==s[sa[rk[i]+1]+k])k++;
      		height[rk[i]]=k;
      		st[rk[i]][0]=k;
      	} 
      	for(int j=1;j<=20;j++){
      		for(int i=1;i+(1<<j)-1<n;i++){
      			st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
      		}
      	}
      	for(int i=1;i<=n;i++){
      		cout<<get(rk[i],rk[1])<<' ';
      	}
      	return 0;
      }
      
      • 0
        @ 2026-8-5 9:22:00

        代码背了但是没读懂。何为 exkmp?

        #include<bits/stdc++.h>
        using namespace std;
        const int N=5e5+10;
        char st[N];int z[N];
        signed main()
        {
        	scanf("%s",st+1);int n=strlen(st+1);
        	z[1]=n;
        	for(int i=2,l=1,r=1;i<=n;i++)
        	{
        		if(i<=r&&z[i-l+1]<r-i+1)z[i]=z[i-l+1];
        		else 
        		{
        			z[i]=max(0,r-i+1);
        			while(i+z[i]<=n&&st[z[i]+1]==st[i+z[i]])z[i]++;
        		}
        		if(i+z[i]-1>r)l=i,r=i+z[i]-1;
        	}
        	for(int i=1;i<=n;i++)cout<<z[i]<<' ';cout<<'\n';
        	return 0;
        }
        • 1

        信息

        ID
        3271
        时间
        1000ms
        内存
        1024MiB
        难度
        7
        标签
        递交数
        20
        已通过
        8
        上传者