zoukankan      html  css  js  c++  java
  • [loj3103]节日庆典

    约定:以下字符串下标从1开始

    对于字符串$s_{1}$和$s_{2}$,定义以下信息——

    定义$s_{1}approx s_{2}$当且仅当$s_{1}[1,l]=s_{2}[1,l]$(其中$l=min(|s_{1}|,|s_{2}|)$)

    定义$s_{1}ll s_{2}$当且仅当$s_{1}<s_{2}$且$s_{1} otapprox s_{2}$,$s_{1}gg s_{2}$当且仅当$s_{1}>s_{2}$且$s_{1} otapprox s_{2}$

    结论:若$s=caab$,则$f(s) e |c|+|a|+1$(其中$a,b,c$为任意字符串,且$a,b$非空)

    考虑取另外$|c|+1$和$|c|+2|a|+1$的位置,即求证$abcale aabc$或$abca<bcaa$

    (前者取等号,因为当相等时,$f(s)$会取靠前的位置)

    当$bcale abc$时,前者显然成立;当$bca>abc$时,后者显然成立

    (另外,当$b$为空时此结论也成立,但本文中并不需要利用此性质)

    $forall xin [1,i]$,$xin S_{i}$当且仅当其满足:

    1.$forall 1le yle i,s[x,i] otll s[y,i]$

    2.$forall 1le y<x且2x-yle i,s[y,i] otapprox s[x,i]$

    (这个条件即等价于不存在$s[1,i]=caab$使得$f(s)=|c|+|a|+1$)

    显然,有$f(s[1,i])in S_{i}$,下面考虑$|S_{i}|$的大小——

    结论:$|S_{i}|sim o(log n)$

    若$x,yin S_{i}$(不妨假设$x<y$),根据第一个性质,则有$s[x,i]approx s[y,i]$

    若$2y-xle i$,即可以得到$s[x,y)=s[y,2y-x)$,与第2个性质矛盾

    因此$2y-x>i$,也即$2|s[y,i]|le |s[x,i]|$,因此将$S_{i}$中的$x$写作$i-x+1$从小到大排列后,后一项大于等于前一项的两倍且值域为$[1,i]$,即有$|S_{i}|sim o(log n)$

    下面,考虑如何求$S_{i}$,显然$S_{i}subseteq S_{i-1}cup {i}$,从小到大枚举$S_{i-1}cup {i}$中的元素$x$,并判定能否加入$S_{i}$中

    关于这里,判定只需要考虑$S_{i}$中的元素(正确性显然),更具体的即如下做法——

    初始$S_{i}$为空,若$S_{i}$为空则直接加入,否则令$y$为当前$S_{i}$中的最大值,考虑$s_{i}$和$s_{y+i-x}$的关系:

    1.$s_{i}>s_{y+i-x}$,不加入$x$

    2.$s_{i}<s_{y+i-x}$,令$S_{i}={x}$

    3.$s_{i}=s_{y+i-x}$,若$2x-y>i$则加入$x$

    初始为$S_{0}=empty$,综上即可求出$S_{i}$,且复杂度为$o(nlog n)$

    最后,考虑如何求$f(s[1,i])$,根据$f(s[1,i])in S_{i}$,可以暴力枚举$S_{i}$中的元素并判定

    下面,我们要快速判定$s[x,i]+s[1,x)$和$s[y,i]+s[1,y)$的大小关系(不妨假设$x<y$),由于$x,yin S_{i}$,因此有$s[x,i]approx s[y,i]$,也即$s[y,i]$是$s[x,i]$的前缀

    换言之,即判定$s(i-(y-x),i]+s[1,x)$和$s[1,y)$的大小关系,考虑求lcp后判定第一个不同的字符,那么问题即求$s$某个后缀与$s$的lcp长度,有以下三种做法:

    1.二分+哈希可以做到$o(log n)$,但总复杂度即变为$o(nlog^{2}n)$,无法通过

    2.后缀数组,复杂度为$o(nlog n)$,常数太大,无法通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 3000005
     4 int n,ans,rk[N<<1],a[N],b[N],c[N],tot[N],sa[N],h[N],v[N],vv[N],num[11];
     5 char s[N];
     6 void write(int x){
     7     while (x){
     8         num[++num[0]]=x%10;
     9         x/=10;
    10     }
    11     for(;num[0];num[0]--)putchar(num[num[0]]+'0');
    12 }
    13 int main(){
    14     scanf("%s",s+1);
    15     n=strlen(s+1);
    16     for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1;
    17     int m=26;
    18     for(int i=1;;i<<=1){
    19         memset(tot,0,sizeof(tot));
    20         for(int j=1;j<=n;j++)tot[rk[j+i]]++;
    21         for(int j=1;j<=m;j++)tot[j]+=tot[j-1];
    22         for(int j=1;j<=n;j++)a[tot[rk[j+i]]--]=j;
    23         memset(tot,0,sizeof(tot));
    24         for(int j=1;j<=n;j++)tot[rk[j]]++;
    25         for(int j=2;j<=m;j++)tot[j]+=tot[j-1];
    26         for(int j=n;j;j--)b[tot[rk[a[j]]]--]=a[j];
    27         m=0;
    28         for(int j=1;j<=n;j++){
    29             if ((j==1)||(rk[b[j]]!=rk[b[j-1]])||(rk[b[j]+i]!=rk[b[j-1]+i]))m++;
    30             c[b[j]]=m;
    31         }
    32         memcpy(rk,c,sizeof(c));
    33         if (m==n)break;
    34     }
    35     for(int i=1;i<=n;i++)sa[rk[i]]=i;
    36     for(int i=1,k=0;i<=n;i++,k-=(k>0)){
    37         while ((i+k<=n)&&(sa[rk[i]+1]+k<=n)&&(s[i+k]==s[sa[rk[i]+1]+k]))k++;
    38         h[rk[i]]=k;
    39     }
    40     for(int i=rk[1]-2;i;i--)h[i]=min(h[i],h[i+1]);
    41     for(int i=n;i>rk[1];i--)h[i]=h[i-1];
    42     h[rk[1]]=n;
    43     for(int i=rk[1]+1;i<=n;i++)h[i]=min(h[i],h[i-1]);
    44     memcpy(c,h,sizeof(c));
    45     for(int i=1;i<=n;i++)h[i]=c[rk[i]];
    46     for(int i=1;i<=n;i++){
    47         for(int j=0;j<=v[0];j++)vv[j]=v[j];
    48         vv[++vv[0]]=i;
    49         v[0]=0;
    50         for(int j=1;j<=vv[0];j++){
    51             if (!v[0])v[++v[0]]=vv[j];
    52             else{
    53                 int x=vv[j],y=v[v[0]];
    54                 if (s[i]<s[y+i-x])v[0]=0;
    55                 if ((s[i]<s[y+i-x])||(s[i]==s[y+i-x])&&(2*x-y>i))v[++v[0]]=x;
    56             }
    57         }
    58         ans=v[1];
    59         for(int j=2;j<=v[0];j++){
    60             int x=ans,y=v[j],l=h[i-(y-x)+1];
    61             if (l<y-x){
    62                 if (s[i-(y-x)+l+1]>s[l+1])ans=y;
    63             }
    64             else{
    65                 l=h[y-x+1];
    66                 if ((l<x-1)&&(s[y-x+l]<s[l+1]))ans=y;
    67             }
    68         }
    69         write(ans);
    70         if (i<n)putchar(' ');
    71     }
    72 } 
    View Code

    3.exkmp,下面将讲述其做法——

    定义数组$z_{i}=lcp(s[i,|s|],s)$(特别的,强制$z_{1}=0$)

    考虑求$z_{i}$,维护一个区间$[l,r]$,其中$r=max_{1le j<i}z_{j}+j-1$,$l$为对应此$r$的最小的$j$

    若$ile r$,根据$s[l,r]=s[1,r-l+1]$,有$s[i,r]=s[l-i+1,r-l+1]$,此时对$z_{i-l+1}$分类讨论:

    1.$z_{i-l+1}<r-i+1$,则$z_{i}=z_{i-l+1}$(如果再增大,即$z_{i-l+1}$也能增大)

    2.$z_{i-l+1}ge r-i+1$,则令$z_{i}=r-i+1$,并暴力增大$z_{i}$扩展

    若$i>r$,则令$z_{i}=0$,并暴力增大$z_{i}$扩展

    最后,再用$[j,z_{j}+j)$去更新$[l,r]$(当$r<z_{j}+j-1$时)

    关于这一做法的正确性显然,考虑时间复杂度:对于两个暴力增大$z_{i}$扩展的情况,都是初始$i+z_{i}-1=r$,之后不断增加$z_{i}$,最终仍令$r=i+z_{i}-1$

    换言之,每一次增加$z_{i}$,不妨同时令$r$增加1,那么显然总复杂度为$o(n)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 3000005
     4 int n,ans,h[N],v[N],vv[N],num[11];
     5 char s[N];
     6 void write(int x){
     7     while (x){
     8         num[++num[0]]=x%10;
     9         x/=10;
    10     }
    11     for(;num[0];num[0]--)putchar(num[num[0]]+'0');
    12 }
    13 int main(){
    14     scanf("%s",s+1);
    15     n=strlen(s+1);
    16     int l=1,r=1;
    17     for(int i=2;i<=n;i++){
    18         if (i<=r){
    19             if (h[i-l+1]<r-i+1)h[i]=h[i-l+1];
    20             else h[i]=r-i+1;
    21         }
    22         while ((i+h[i]<=n)&&(s[i+h[i]]==s[h[i]+1]))h[i]++;
    23         if (i+h[i]-1>r){
    24             l=i;
    25             r=i+h[i]-1;
    26         }
    27     }
    28     h[1]=n;
    29     for(int i=1;i<=n;i++){
    30         for(int j=0;j<=v[0];j++)vv[j]=v[j];
    31         vv[++vv[0]]=i;
    32         v[0]=0;
    33         for(int j=1;j<=vv[0];j++){
    34             if (!v[0])v[++v[0]]=vv[j];
    35             else{
    36                 int x=vv[j],y=v[v[0]];
    37                 if (s[i]<s[y+i-x])v[0]=0;
    38                 if ((s[i]<s[y+i-x])||(s[i]==s[y+i-x])&&(2*x-y>i))v[++v[0]]=x;
    39             }
    40         }
    41         ans=v[1];
    42         for(int j=2;j<=v[0];j++){
    43             int x=ans,y=v[j],l=h[i-(y-x)+1];
    44             if (l<y-x){
    45                 if (s[i-(y-x)+l+1]>s[l+1])ans=y;
    46             }
    47             else{
    48                 l=h[y-x+1];
    49                 if ((l<x-1)&&(s[y-x+l]<s[l+1]))ans=y;
    50             }
    51         }
    52         write(ans);
    53         if (i<n)putchar(' ');
    54     }
    55 } 
    View Code
  • 相关阅读:
    OpenCascade Ray Tracing Rendering
    Create New Commands in Tcl
    OpenCascade Modeling Algorithms Fillets and Chamfers
    OpenCascade Modeling Algorithms Boolean Operations
    Construction of Primitives in Open Cascade
    Open Cascade Data Exchange STL
    Tcl Tk Introduction
    Open Cascade DataExchange IGES
    Netgen mesh library : nglib
    Hello Netgen
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14785609.html
Copyright © 2011-2022 走看看