zoukankan      html  css  js  c++  java
  • bzoj 2119 股市的预测 —— 枚举关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119

    思路就是对于这个形如 ABA 的串,枚举 A 的长度,并按照长度分出几块,找到一些关键点就是块的开头;

    那么每一种 ABA 的串,A 的部分一定覆盖了一个关键点;

    所以找关键点周围的匹配长度算答案,具体就是找和对应位置的 lcp + lcs,那么 ABA 可以在对应匹配的地方滑动,就能找到所有 ABA 了;

    因为是差分数组所以 n-1,而且注意连接正反串的字符要比串内字符小,不是 '0'-1 而是 0 ...

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int Min(int x,int y){return x<y?x:y;}
    int const xn=1e5+5;
    int n,mx,d,m,s[xn],t[xn],tt[xn],tax[xn],sa[xn],rk[xn],tp[xn];
    int op[xn],ht[xn][20],bin[20],bit[xn];
    void rsort()
    {
      for(int i=1;i<=m;i++)tax[i]=0;
      for(int i=1;i<=mx;i++)tax[rk[tp[i]]]++;
      for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
      for(int i=mx;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void work()
    {
      for(int i=1;i<=mx;i++)rk[i]=s[i],tp[i]=i;
      m=n; rsort();
      for(int k=1;k<=mx;k<<=1)
        {
          int num=0;
          for(int i=mx-k+1;i<=mx;i++)tp[++num]=i;
          for(int i=1;i<=mx;i++)
        if(sa[i]>k)tp[++num]=sa[i]-k;
          rsort(); swap(rk,tp);
          rk[sa[1]]=1; num=1;
          for(int i=2;i<=mx;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
          if(num==mx)break;
          m=num;
        }
    }
    void geth()
    {
      int k=0;
      for(int i=1;i<=mx;i++)
        {
          if(rk[i]==1)continue;
          if(k)k--; int j=sa[rk[i]-1];
          while(s[i+k]==s[j+k]&&i+k<=mx&&j+k<=mx)k++;
          ht[rk[i]][0]=k;
        }
      bin[0]=1; for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
      bit[1]=0; for(int i=2;i<=mx;i++)bit[i]=bit[i>>1]+1;
      for(int i=1;i<20;i++)
        for(int j=1;j+bin[i]-1<=mx;j++)
          ht[j][i]=Min(ht[j][i-1],ht[j+bin[i-1]][i-1]);
    }
    int getlcp(int x,int y)
    {
      if(x==y)return mx-x+1;
      x=rk[x]; y=rk[y];
      if(x>y)swap(x,y); x++;
      int r=bit[y-x+1];
      return Min(ht[x][r],ht[y-bin[r]+1][r]);
    }
    int main()
    {
      n=rd(); d=rd();
      for(int i=1;i<=n;i++)t[i]=rd();
      for(int i=n;i>1;i--)t[i]=t[i]-t[i-1],tt[i]=t[i];
      sort(t+1,t+n+1); int tot=unique(t+1,t+n+1)-t-1;
      for(int i=2;i<=n;i++)tt[i]=lower_bound(t+1,t+tot+1,tt[i])-t;
      n--; mx=2*n+1;
      for(int i=1;i<=n;i++)s[i]=tt[i+1];
      s[n+1]=0;//0
      for(int i=n+2,k=n;k;i++,k--)s[i]=s[k],op[k]=i;
      work(); geth(); int ans=0;
      for(int k=1;k<=n;k++)
        for(int i=1;i+k+d<=n;i+=k)
          {
        int j=i+k+d;
        int l1=getlcp(i,j),l2=getlcp(op[i],op[j]);
        l1=Min(l1,k); l2=Min(l2,k);
        if(l1&&l2&&l1+l2-1>=k)ans+=l1+l2-1-k+1;
        else if(l1&&l1>=k)ans+=l1-k+1;
        else if(l2&&l2>=k)ans+=l2-k+1;
          }
      printf("%d
    ",ans);
      return 0;
    }
  • 相关阅读:
    C语言 递归 汉诺塔问题 最大公约数问题
    程序的健壮性及代码风格
    C程序练习
    专题——条件控制循环 猜数游戏 随机种子
    C语言 分支与循环 递推思想 穷举 流程的转移控制
    C指针 指针和数组 二维数组的指针 指针应用
    C语言实现的排序
    数组查找算法的C语言 实现-----线性查找和二分查找
    图片转成base64 跨域等安全限制及解决方案
    移动开发那些坑之——safari mobile click事件的冒泡bug
  • 原文地址:https://www.cnblogs.com/Zinn/p/10325682.html
Copyright © 2011-2022 走看看