• 【字符串杂谈】


    前言

    树真的花了好久。。
    还剩下\(LCT\)没有学,等最后一周板刷联合省选,遇到的话再学了
    现在是字符串时间
    \(Hash\)\(Kmp\)自然不用说了

    \(Machacher\)

    挂个板子好了

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 30000000
    
    char a,s[N];
    ll len = 0,m,ans[N],fans;
    
    int main(){
    	s[0] = '~';
    	a = getchar();
    	while(a <= 'z' && a >= 'a'){
    		s[++len] = '|';
    		s[++len] = a;
    		a = getchar();
    	}
    	s[++len] = '|';
    	for(int i = 1;i <= len;++i){
    		if(m + ans[m] >= i)
    		ans[i] = std::min(m + ans[m] - i,ans[m * 2 - i]);
    		while(s[i - ans[i]] == s[i + ans[i]]) ans[i] ++ ;
    		if(ans[i] + i > m + ans[m])m = i;
    		if(fans < ans[i])
    		fans = ans[i];
    	} 
    	std::cout<<fans - 1;
    }
    

    [THUPC2018]绿绿和串串

    [THUPC2018]绿绿和串串
    考虑对于一个串是否可以进行判定,要么以这个字符为中心的回文串的最右端到\(T\)的最右端,要么以这个字符为中心的回文串的最右端属于可以的答案,以及以这个字符为中心的回文串的最左端为1

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 1000005
    
    ll ans[N << 1];
    char s[N << 1];
    bool y[N << 1];
    
    int t,len = 0;
    
    void ma(){
    	ll m = 0;
    	len = 0;
    	char c = getchar();
    	while(c > 'z' || c < 'a')
    	c = getchar();
    	s[len] = '~';
    	while(c <= 'z' && c >= 'a')
    	s[++len] = '|',s[++len] = c,c = getchar();
    	s[++len] = '|';
    	s[len + 1] = '\0';
    	for(int i = 1;i <= len;++i){
    		ans[i] = 0;
    		if(m + ans[m] >= i)
    		ans[i] = std::min(m + ans[m] - i,ans[(m << 1) - i]);
    		while(s[i + ans[i]] == s[i - ans[i]]) ++ ans[i];
    		if(i + ans[i] > m + ans[m])
    		m = i;
    	}
    }
    
    int main(){
    	scanf("%d",&t);
    	while(t -- ){
    		ma();
    		for(int i = len;i >= 1;--i){
    			y[i] = 0;
    			y[i] = ((i + ans[i] - 1) == len) || ((i - ans[i] + 1 == 1) && (y[i + ans[i] - 2]));
    		}
    		for(int i = 2;i <= len;i += 2)
    		if(y[i])
    		printf("%d ",i >> 1);
    		puts("");
    	}
    }
    

    最小表示法

    最小表示法
    考虑对暴力进行一个优化,如果对于两个串\(s[i....],s[j....]\)\(k\)处不同,那么如果\(s[i + k] > s[j + k]\)对于\(s[i + 1..],s[i + 2...]...s[i + k...]\)就都没有\(s[j]\)优,那么\(i = i + k + 1\)如果相反那么我们把\(i,j\)调过来就行了,我们始终维护\(j\)为最优解

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 300005
    
    ll n;
    
    ll a[N << 1];
    
    int main(){
    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i)
    	scanf("%lld",&a[i]);
    	for(int i = n + 1;i <= 2 * n;++i)
    	a[i] = a[i - n];
    	int j = 1,i = 2,k,tmp;
    	while(i <= n){
    		k = 0;
    		while(a[i + k] == a[j + k])
    		k += 1;
    		if(a[i + k] < a[j + k])
    		tmp = i,i = std::max(i + 1,j + k + 1),j = tmp;
    		else
    		i = i + k + 1;
    	}
    	for(int l = 1;l <= n;++l)
    	std::cout<<a[j + l - 1]<<" ";
    }
    

    [TJOI2017]DNA

    [TJOI2017]DNA
    考虑进行暴力,因为要进行暴力,那么我们需要求出\(LCP\)
    现有一个结论字典序为\(u,v\)的两个后缀,他们的\(LCP\)\(min(height[u...v])\)倍增和线段树都能做。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1e6 + 5;
    int rk[maxn], RK[maxn];
    int sa[maxn], SA[maxn];
    int bac[maxn], n, h[maxn], height[maxn];
    int rmq[maxn][18], bin[1 << 18];
    char str[maxn];
    
    void getsa(char *str, int n, int alp = 256) {
        for (int i = 0; i <= alp; i++) bac[i] = 0;
        for (int i = 1; i <= n; i++) ++bac[str[i]];
        for (int i = 1; i <= alp; i++) bac[i] += bac[i - 1];
        for (int i = 1; i <= n; i++) sa[bac[str[i]]--] = i;
        for (int i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (str[sa[i]] != str[sa[i - 1]]);
    
        for (int p = 1; p <= n; p <<= 1)
        {
            for (int i = 1; i <= n; i++) bac[rk[sa[i]]] = i;
            for (int i = n; i >= 1; i--) if (sa[i] > p) SA[bac[rk[sa[i] - p]]--] = sa[i] - p;
            for (int i = n; i > n - p; i--) SA[bac[rk[i]]--] = i;
            #define comp(x, y) (rk[x] != rk[y] || rk[x + p] != rk[y + p])
            for (int i = 1; i <= n; i++) RK[SA[i]] = RK[SA[i - 1]] + comp(SA[i], SA[i - 1]);
            for (int i = 1; i <= n; i++) sa[i] = SA[i], rk[i] = RK[i];
            if (rk[sa[n]] >= n) return ;
        }
    }
    void geth(char *str, int n) {
        for (int i = 1; i <= n; i++)
        {
            int j = sa[rk[i] - 1], k = max(0, h[i - 1] - 1);
            while (str[i + k] == str[j + k] && str[i + k]) ++k;
            h[i] = height[rk[i]] = k;
        }
        for (int j = 0; j < 18; j++)
        for (int i = 1 << j; i < (1 << j + 1); i++) bin[i] = j;
        for (int i = 1; i <= n; i++) rmq[i][0] = height[i];
        for (int j = 1; j < 18; j++)
        for (int i = 1 << j; i <= n; i++)
            rmq[i][j] = min(rmq[i - (1 << j - 1)][j - 1], rmq[i][j - 1]);
    }
    int lcp(int x, int y) {
        int u = rk[x], v = rk[y];
        if (u > v) swap(u, v);
        int j = bin[v - u];
        return min(rmq[v][j], rmq[u + (1 << j)][j]);
    }
    
    int main()
    {
        int T; for (scanf("%d", &T); T--; )
        {
            scanf("%s", str + 1);
            n = strlen(str + 1);
            str[n + 1] = '@';
            int j = n + 1; 
            scanf("%s", str + n + 2);
            n = strlen(str + 1);
            int m = n - j; 
            getsa(str, n); geth(str, n);
            int ans = 0;
            for (int i = 1; i + m <= j; i++)
            {
                int p = lcp(i, j + 1) + 1;
                for (int k = 1; k <= 3 && p <= m; k++)
                    p += lcp(i + p, j + p + 1) + 1;
                ans += (p > m);
            }
            printf("%d\n", ans);
        }
    }
    

    \(AC\)自动机

    挂板子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define ll long long
    
    ll n,cnt;
    int to[1000005][50],end[1000005],fail[1000005];
    char a[1000005];
    
    void insert(){
    	ll now = 0;
    	ll n = strlen(a + 1);
    	for(int i = 1;i <= n;++i){
    		if(!to[now][a[i] - 'a'])
    		to[now][a[i] - 'a'] = ++ cnt ;
    		now = to[now][a[i] - 'a'];
    	}
    	end[now] ++ ;
    }
    
    std::queue<int>	QWQ ;
    
    void get(){
    	for(int i = 0;i < 26;++i)
    	if(to[0][i]) fail[to[0][i]] = 0,QWQ.push(to[0][i]);
    	while(! QWQ.empty()){
    		ll u = QWQ.front();QWQ.pop();
    		for(int i = 0;i < 26;++i)
    		if(to[u][i]) fail[to[u][i]] = to[fail[u]][i],QWQ.push(to[u][i]);
    		else to[u][i] = to[fail[u]][i]; 
    	}
    }
    
    int query(){
    	ll len = strlen(a + 1),now = 0,ans = 0;
    	for(int i = 1;i <= len;++i){
    		now = to[now][a[i] - 'a'];
    		for(int t = now;t && end[t] != -1;t = fail[t]) ans += end[t],end[t] = -1;
    	}
    	return ans;
    }
    
    int main(){
    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i){
    		scanf("%s",a + 1);
    		insert();
    	}
    	get();
    	scanf("%s",a + 1);
    	std::cout<<query()<<std::endl;
    }
    

    [POI2000]病毒

    [POI2000]病毒
    考虑建完\(AC\)自动机,那么此时自动机是一个有向图,那么如果出现环就是一个安全的代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define ll long long
    
    ll n,cnt;
    
    using std::queue;
    
    char num[30005];
    
    ll trie[40000][5],fail[40000];
    
    bool end[40000];
    
    void insert(){
    	ll now = 0;
    	ll len = strlen(num + 1);
    	for(int i = 1;i <= len;++i){
    		if(!trie[now][num[i] - '0'])
    		++cnt,trie[now][num[i] - '0'] = cnt;;
    		now = trie[now][num[i] - '0'];
    	}
    	end[now] = 1;
    }
    
    queue<int>QWQ;
    
    void get_fail(){
    	for(int i = 0;i <= 1;++i)
    	if(trie[0][i]) fail[trie[0][i]] = 0,QWQ.push(trie[0][i]);
    	while(!QWQ.empty()){
    		int u = QWQ.front();QWQ.pop();
    		for(int i = 0;i <= 1;++i){
    		if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],QWQ.push(trie[u][i]);
    		else trie[u][i] = trie[fail[u]][i];
    		if(end[trie[fail[u]][i]])
    		end[trie[u][i]] = 1;
    		}
    	}
    }
    
    bool ins[40000],used[40000];
    
    bool get(ll now){
    	ins[now] = 1;
    	for(int i = 0;i < 2;++i){
    		int v = trie[now][i];
    		if(ins[v]) return 1;
    		if(used[v] || end[v]) continue;
    		used[v] = 1;
    		if(get(v)) return 1;
    	}
    	ins[now] = 0;
    	return 0;
    } 
    
    int main(){
    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i){
    		scanf("%s",num + 1);
    		insert();
    	}
    	get_fail();	
    	if(get(0))
    	puts("TAK");
    	else
    	puts("NIE");
    }
    

    阿狸的自动机

    先咕一下

  • 相关阅读:
    @RequestParam方式传入list
    编写优美代码的七条规范(Python版)
    汇编程序设计入门
    CSP-S2020解题报告(待完成!)
    [USACO18JAN]MooTube
    DP优化
    AFO记
    考前总结
    清北学堂周末刷题班第五场
    清北学堂考前综合刷题班第四场
  • 原文地址:https://www.cnblogs.com/dixiao/p/14555927.html
Copyright © 2020-2023  润新知