• 洛谷 P5334 [JSOI2019]节日庆典


    题意即为求每个前缀的最小循环表示。

    考虑维护当前可能成为答案的后缀,因为当前的最小后缀加上前面一段后不一定仍最小,所以对于所有前缀为最小后缀的后缀都要进行考虑。

    但是这样候选后缀会有很多,复杂度无法接受。发现对于两个后缀 (a,b),若 (|a|<|b|<2|a|),则 (a) 一定不优,这样候选后缀就为 (O(log n)) 个了。

    用扩展 (KMP) 预处理后就可以快速比较两个后缀。

    #include<bits/stdc++.h>
    #define maxn 3000010
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,l,r;
    int z[maxn];
    char s[maxn];
    vector<int> ve;
    int main()
    {
        scanf("%s",s+1),z[1]=n=strlen(s+1);
        for(int i=2;i<=n;++i)
        {
            if(i<=r) z[i]=min(z[i-l+1],r-i+1);
            while(i+z[i]<=n&&s[i+z[i]]==s[z[i]+1]) z[i]++;
            if(i+z[i]-1>r) l=i,r=i+z[i]-1;
        }
        for(int i=1;i<=n;++i)
        {
            vector<int> tmp;
            ve.push_back(i);
            for(int j=0;j<ve.size();++j)
            {
                int p=ve[j];
                while(!tmp.empty()&&s[i]<s[tmp.back()+i-p]) tmp.pop_back();
                if(tmp.empty()||(s[i]==s[tmp.back()+i-p]&&2*(i-p+1)<=i-tmp.back()+1)) tmp.push_back(p);
            }
            ve=tmp;
            int pos=ve[0];
            for(int j=1;j<ve.size();++j)
            {
                int p=ve[j],x=pos+i-p+1;
                if(z[x]>=p-pos)
                {
                    x=p-pos+1;
                    if(z[x]<pos-1&&s[z[x]+1]>s[x+z[x]]) pos=p;
                }
                else if(s[z[x]+1]<s[x+z[x]]) pos=p;
            }
            printf("%d ",pos);
        }
        return 0;
    }
    
  • 相关阅读:
    php获取OS信息
    坑爹的IE quirk模式
    [转]mysql privileges
    [转]VSFTPD的设置选项
    php性能分析工具xhprof
    php扩展安装
    又是万恶的IE....6
    ASP.NET操作文件(文件夹)简单生成html操作示例
    asp.net文件操作类
    c++/clr与c#的性能比较
  • 原文地址:https://www.cnblogs.com/lhm-/p/14122788.html
Copyright © 2020-2023  润新知