• 牛客挑战赛39 密码系统 后缀数组


    LINK:密码系统

    容易发现一共有k种不同的划分 而每种划分中我们要求出字典序最大的那个然后和其他的比较求出字典序最小的。

    先考虑如何求出最大的 容易发现这是字典序的问题 求出sa数组然后倒着扫描就行了 分段的话按i%k分即可。

    求出最大的了之后考虑如何求出最小的 容易发现还是sa数组看一下他们之间的相对位置 靠前的必然字典序要优。

    值得一提的是 后缀数组虽然难写 但是思想很好懂 按照思想来写不容易写错 而不是靠硬背。

    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ldb long double
    #define pb push_back
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define pii pair<int,int> 
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define S second
    #define F first
    #define mod 998244353
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define ull unsigned long long
    #define ui unsigned
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=1000010<<1;
    int n,m,k;
    char a[MAXN];int vis[MAXN];
    int c[MAXN],x[MAXN],y[MAXN],sa[MAXN],rk[MAXN],h[MAXN];
    inline void SA()
    {
    	m=150;
    	rep(1,n,i)++c[x[i]=a[i]];
    	rep(1,m,i)c[i]+=c[i-1];
    	rep(1,n,i)sa[c[x[i]]--]=i;
    	for(int k=1;k<=n;k=k<<1)
    	{
    		int num=0;
    		rep(n-k+1,n,i)y[++num]=i;
    		rep(1,n,i)if(sa[i]>k)y[++num]=sa[i]-k;
    		rep(1,m,i)c[i]=0;
    		rep(1,n,i)++c[x[i]];
    		rep(1,m,i)c[i]+=c[i-1];
    		fep(n,1,i)sa[c[x[y[i]]]--]=y[i];
    		rep(1,n,i)y[i]=x[i],x[i]=0;
    		x[sa[1]]=num=1;
    		rep(2,n,i)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?num:++num;
    		if(num==n)break;
    		m=num;
    	}
    	rep(1,n,i)rk[sa[i]]=i;
    }
    inline void get_H()
    {
    	int k=0;
    	rep(1,n,i)
    	{
    		if(rk[i]==1)continue;
    		if(k)--k;
    		int j=sa[rk[i]-1];
    		while(a[i+k]==a[j+k])++k;
    		h[rk[i]]=k;
    	}
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	gt(n);gt(k);gc(a);
    	rep(1,n,i)a[i+n]=a[i];
    	n=n<<1;SA();get_H();
    	//rep(1,n,i)put(rk[i]);
    	int en=k+n/2-1,st;//有效部分.
    	fep(n,1,i)
    	{
    		if(sa[i]>en)continue;
    		int ww=sa[i]%k;
    		if(vis[ww])continue;
    		vis[ww]=1;st=i;
    	}
    	rep(sa[st],sa[st]+k-1,i)putchar(a[i]);
    	return 0;
    }
    
  • 相关阅读:
    Eclipse运行单个Junit 单元测试
    梯形法求定积分(一)设计梯形法求积分的类模板,梯形法
    写一个顺序表模板,包括顺序表的基本功能,例如查找,插
    对于静态成员函数和静态成员变量的练习
    梯形法求定积分(二)设计一个函数模板,独立的非成员函
    各位高手帮我看看这个清屏程序
    对于静态成员函数和静态成员变量的练习
    二分法的递归算法和迭代算法,算法作为有序表模板类的成
    梯形法求定积分(一)设计梯形法求积分的类模板,梯形法
    二分法的递归算法和迭代算法,算法作为有序表模板类的成
  • 原文地址:https://www.cnblogs.com/chdy/p/12745883.html
Copyright © 2020-2023  润新知