2 条题解

  • 0
    @ 2025-10-8 17:06:03

    本题就是求重复数最多的字典序最小的runs,如果重复数为1,那么做法显然,然后只考虑重复数大于1的情况。 从小到大枚举长度len,对于每个关键点x=i×len,有且仅有一个长度为len的串经过它。 算出x与x+len的最长公共前缀A 和最长公共后缀B后,贡献为⌊(A+B−1)/len⌋+1。 对于方案,可以暴力枚举所有可行起点,因为极大runs的总个数是O(n)的。时间复杂度O(nlog2n)。

    #include<cstdio>
    #include<cstring>
    typedef unsigned long long ll;
    const int N=100010,D=13331;
    int T,n,m,i,j,k,x,y,A,B,L,ans,st,en;char a[N];ll pow[N],f[N];
    inline ll hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
    inline int min(int a,int b){return a<b?a:b;}
    inline int lcp(int x,int y){
      if(a[x]!=a[y])return 0;
      int l=2,r=min(n-x,n-y)+1,mid,t=1;
      while(l<=r){
        mid=(l+r)>>1;
        if(hash(x,x+mid-1)==hash(y,y+mid-1))l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    inline int lcs(int x,int y){
      int l=2,r=x,mid,t=1;
      while(l<=r){
        mid=(l+r)>>1;
        if(hash(x-mid+1,x)==hash(y-mid+1,y))l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    inline void up(int x,int y){
      if(k>ans){ans=k,st=x,en=y;return;}
      int l0=en-st+1,l1=y-x+1,t=min(lcp(x,st),min(l0,l1));
      if((t<l1?a[x+t]:0)<(t<l0?a[st+t]:0))st=x,en=y;
    }
    int main(){
      scanf("%d",&T);
      for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D;
      while(T--){
        scanf("%s",a+1);n=strlen(a+1);
        for(ans=i=st=en=1;i<=n;i++)if(a[i]<a[st])st=en=i;
        for(i=1;i<=n;i++)f[i]=f[i-1]*D+a[i];
        for(i=1;i+i<=n;i++)for(j=i;j<=n;j+=i){
          x=j+i;
          if(x>n)break;
          if(a[j]!=a[x])continue;
          A=lcp(j,x),B=lcs(j,x),k=(A+B-1)/i+1;
          if(k>=ans&&k>1)for(L=k*i,y=j-B+1;y+L<=i+j+A;y++)up(y,y+L-1);
        }
        for(i=st;i<=en;i++)putchar(a[i]);puts("");
      }
      return 0;
    }
    
    • 0
      @ 2025-10-8 17:05:55
      /*
      本题就是求重复数最多的字典序最小的runs,如果重复数为1,那么做法显然,然后只考虑重复数大于1的情况。
      从小到大枚举长度len,对于每个关键点x=i×len,有且仅有一个长度为len的串经过它。
      算出x与x+len的最长公共前缀A
      和最长公共后缀B后,贡献为⌊(A+B−1)/len⌋+1。
      对于方案,可以暴力枚举所有可行起点,因为极大runs的总个数是O(n)的。时间复杂度O(nlog2n)。
      */
      #include<cstdio>
      #include<cstring>
      typedef unsigned long long ll;
      const int N=100010,D=13331;
      int T,n,m,i,j,k,x,y,A,B,L,ans,st,en;char a[N];ll pow[N],f[N];
      inline ll hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
      inline int min(int a,int b){return a<b?a:b;}
      inline int lcp(int x,int y){
        if(a[x]!=a[y])return 0;
        int l=2,r=min(n-x,n-y)+1,mid,t=1;
        while(l<=r){
          mid=(l+r)>>1;
          if(hash(x,x+mid-1)==hash(y,y+mid-1))l=(t=mid)+1;else r=mid-1;
        }
        return t;
      }
      inline int lcs(int x,int y){
        int l=2,r=x,mid,t=1;
        while(l<=r){
          mid=(l+r)>>1;
          if(hash(x-mid+1,x)==hash(y-mid+1,y))l=(t=mid)+1;else r=mid-1;
        }
        return t;
      }
      inline void up(int x,int y){
        if(k>ans){ans=k,st=x,en=y;return;}
        int l0=en-st+1,l1=y-x+1,t=min(lcp(x,st),min(l0,l1));
        if((t<l1?a[x+t]:0)<(t<l0?a[st+t]:0))st=x,en=y;
      }
      int main(){
        scanf("%d",&T);
        for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D;
        while(T--){
          scanf("%s",a+1);n=strlen(a+1);
          for(ans=i=st=en=1;i<=n;i++)if(a[i]<a[st])st=en=i;
          for(i=1;i<=n;i++)f[i]=f[i-1]*D+a[i];
          for(i=1;i+i<=n;i++)for(j=i;j<=n;j+=i){
            x=j+i;
            if(x>n)break;
            if(a[j]!=a[x])continue;
            A=lcp(j,x),B=lcs(j,x),k=(A+B-1)/i+1;
            if(k>=ans&&k>1)for(L=k*i,y=j-B+1;y+L<=i+j+A;y++)up(y,y+L-1);
          }
          for(i=st;i<=en;i++)putchar(a[i]);puts("");
        }
        return 0;
      }
      • 1

      信息

      ID
      3985
      时间
      1000ms
      内存
      128MiB
      难度
      10
      标签
      递交数
      1
      已通过
      1
      上传者