• 字符串模板


    模板

    next数组

    //下标从0开始
    int Next[maxn];//Next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    void next_pre(int m){
    	int i,j;
    	j=Next[0]=-1;//检测到j==-1时就停止迭代
    	i=0;
    	while(i<m){
    		while(-1!=j &&p[i]!=p[j])j=Next[j];
    		Next[++i]=++j;
    	}
    }
    

    kmp

    可以统计模式串的出现次数

    //洛谷P3375,输出s2在s1中出现的每个位置,答案的下标从1开始
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 5;
    int nxt[N];
    char s1[N], s2[N];
    void get_next(char* s,int l, int* nxt) { // s是模式串
        int i = 0, j = -1;
        nxt[0] = -1;
        while(i < l) {
            if(j == -1 || s[i] == s[j])
                nxt[++i] = ++j;
            else j = nxt[j];
        }
    }
    void kmp(char* p, char* s, int m, int n, int* nxt) { // p是模式串,s是文本串
        int i = 0, j = 0;
        while (i < n) {
            if(j == -1 || s[i] == p[j]) i++, j++;
            else j = nxt[j];
            if(j == m) printf("%d\n", i-m+1), j = nxt[j];
        }
    }
    int main() {
        scanf("%s%s", s1, s2);
        int len1=strlen(s1);
        int len2=strlen(s2);
        get_next(s2,len2,nxt);
        kmp(s2,s1,len2,len1,nxt);
        for (int i = 1; i <= strlen(s2); i++)
            printf("%d ", nxt[i]);
    }
    
    //下标从0开始
    int kmpNext[maxn];// kmpNext[i] 的意思:next'[i]=next[next[...[next[i]]]](直到 next'[i]<0 或者 x[next'[i]]!=x[i]) ,在kmp用这种数组更快(用Next也可以)。
    void kmp_pre(int m){
    	int i,j;
    	j=kmpNext[0]=-1;
    	i=0;
    	while(i<m){
    		while(-1!=j && p[i]!=p[j]) j=kmpNext[j];
    		if(p[++i]==p[++j])kmpNext[i]=kmpNext[j];
    		else kmpNext[i]=j;
    	}
    }
    int kmp(int n,int m){
    	int i=0,j=0;
    	while(i<n&&j<m){
    		if(j==-1 || a[i]==p[j]){//模式串首位就失配后,j==-1
    			i++;j++;
    		}
    		else j=kmpNext[j];
    	}
    	if(j==m) return i-m;
    	else return -1;
    }
    

    manachar

    char s[maxn],s1[maxn];
    int p[maxn];
    int manacher(int n){
    	int ans=0;
    	s1[0]='~';
    	s1[1]='#';
    	int cnt=1;
    	for(int i=0;i<n;i++){
    		s1[++cnt]=s[i];
    		s1[++cnt]='#';
    	}
    	int maxr=0,mid=0;
    	for(int i=1;i<=cnt;i++){
    		if(i<maxr)
    			p[i]=min(p[(mid<<1)-i],maxr-i);//对称回文的长度和
    		else p[i]=1;//p[i]为半径(包括原点)
    		while(s1[i-p[i]]==s1[i+p[i]]){
    			p[i]++;
    		}
    		if(i+p[i]-1>maxr){//看别人都是i+p[i]>maxr,不知道为啥
    			maxr=i+p[i]-1;
    			mid=i;
    		}
    		if(p[i]>ans) ans=p[i];
    	}
    	return ans-1;
    }
    int main(){
    	while(~scanf("%s",s) ){
    		int n=strlen(s);
    		printf("%d\n",manacher(n));
    	}
    }
    

    例题

    模式串计数

    https://cn.vjudge.net/contest/316613#problem/B

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn=1e6+5;
    int Next[maxn];//next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    char p[maxn];
    char a[maxn];
    void next_pre(int m){
    	int i,j;
    	j=Next[0]=-1;
    	i=0;
    	while(i<m){
    		while(-1!=j &&p[i]!=p[j])j=Next[j];
    		Next[++i]=++j;
    	}
    }
    int kmpc(int n,int m){
    	int i=0,j=0;
    	int ans=0;
    	while(i<n){
    		if(j==-1 || a[i]==p[j]){
    			if(j==m-1){
    				ans++;
    				j=Next[j+1]-1;//模式串指针跳到自身的最大前缀后缀匹配下标
    			}
    			else{
    				i++;j++;
    			}
    		}
    		else j=Next[j];
    	}
    	return ans;
    }
    int main(){
    	int t,n,m;
    	cin>>t;
    	while(t--){
    		scanf("%s",p);
    		scanf("%s",a);
    		n=strlen(a);
    		m=strlen(p);
    		next_pre(m);
    		int temp=kmpc(n,m);
    		printf("%d\n",temp);
    	}
    }
    

    Compress Words

    https://codeforces.com/contest/1200/problem/E

    题意:给定一些字符串,把前缀后缀相同的缩掉拼起来

    由于每个串最长有1e6,存储的时候不能直接开一个大二维数组,可以开两个一维数组交替存储

    从前往后遍历,把答案储存在ans[]数组中,当下一个字符串长度为l时,从答案串中拿出后l个字符拼到新串之后做一次next[]数组计算,由于start=next[l+l]可能>l,所以要递归到next[start]<=l为止( [0,start-1]和[start,l+l]相同,那么[0,start]的最大前缀后缀相同长度就是整个串的前缀后缀相同长度 )

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn=1e6+5;
    char p[maxn];
    int Next[maxn];//Next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    void next_pre(int m){
        int i,j;
        j=Next[0]=-1;//检测到j==-1时就停止迭代
        i=0;
        while(i<m){
            while(-1!=j &&p[i]!=p[j])j=Next[j];
            Next[++i]=++j;
        }
    }
    char c1[maxn],c2[maxn],ans[maxn];
    int l1,l2,len=0;
    int main(){
    	int n,m,q;
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		if(i&1){
    			scanf("%s",c1);
    			l1=strlen(c1);
    		}
    		else{
    			scanf("%s",c2);
    			l2=strlen(c2);
    		}
    		if(i>1){
    			int temp,start,minn;
    			if(i&1){//c1
    				for(int j=0;j<l1;j++) p[j]=c1[j];
    				for(int j=max(0,len-l1),k=l1;j<len;j++,k++)
    					p[k]=ans[j];
    				temp=l1+min(l1,len);
    				minn=min(l1,len);
    			}
    			else{
    				for(int j=0;j<l2;j++) p[j]=c2[j];
    				for(int j=max(0,len-l2),k=l2;j<len;j++,k++)
    					p[k]=ans[j];
    				temp=l2+min(l2,len);
    				minn=min(l2,len);
    			}
    			next_pre(temp);
    			start=Next[temp];
    			while(start>minn) start=Next[start];//这是关键
    			if(start<=0)start=0;
    			if(i&1){
    				start=min(start,Next[temp]);
    				for(int j=start,k=len;j<l1;j++,k++)
    					ans[k]=c1[j];
    				len+=l1-start;
    			}
    			else{
    				for(int j=start,k=len;j<l2;j++,k++)
    					ans[k]=c2[j];
    				len+=l2-start;
    			}
    		}
    		else{
    			for(int j=0;j<l1;j++)
    				ans[j]=c1[j];
    			len=l1;
    		}
    	}
    	for(int j=0;j<len;j++) printf("%c",ans[j]);
    	printf("\n");
    }
    
  • 相关阅读:
    jvm-java内存模型与锁优化
    jvm-垃圾收集器与内存分配策略
    jvm-内存区域与内存溢出异常
    并发-AQS源码分析
    并发-Synchronized底层优化(偏向锁、轻量级锁)
    并发-CopyOnWrite源码分析
    并发-AtomicInteger源码分析—基于CAS的乐观锁实现
    【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法
    【BZOJ】1086: [SCOI2005]王室联邦
    【BZOJ】4358: permu 莫队算法
  • 原文地址:https://www.cnblogs.com/ucprer/p/11315945.html
Copyright © 2020-2023  润新知