BZOJ2119: 股市的预测(后缀数组)

Description

墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势。股票折线图是研究股票的必备工
具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况。经过长时间的观测,墨墨发现很多股
票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A部分的股价和C部分的股价的走势
如出一辙。通过这个观测,墨墨认为他可能找到了一个预测股票未来走势的方法。进一步的研究可是难住了墨墨,
他本想试图统计B部分的长度与发生这种情况的概率关系,不过由于数据量过于庞大,依赖人脑的力量难以完成,
于是墨墨找到了善于编程的你,请你帮他找一找给定重现的间隔(B部分的长度),有多少个时间段满足首尾部分
的走势完全相同呢?当然,首尾部分的长度不能为零。

Input

第一行包含两个整数N、M,分别表示需要统计的总时间以及重现的间隔(B部分的长度)。
接下来N行,每行一个整数,代表每一个时间点的股价。
4≤N≤50000 1≤M≤10 M≤N 所有出现的整数均不超过32位含符号整数。

Output

输出一个整数,表示满足条件的时间段的个数

Sample Input

12 4
1 2 3 4 8 9 1 2 3 4 8 9

Sample Output

6

解题思路:

还是很佩服后缀数组的思维。

这是求一个具有ABA结构的字符串个数。

发现一个性质,如果左右A足够长,

就可以将中间部分左右移动得到新答案。

枚举A的长度L,按L分块,边缘设为关键点。

易知关键点只能被一个串覆盖一次。

只需正反构建后缀数组求Lcp即可。

时间复杂度n(lnn+logn)

代码:

  1 #include<map>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const int N=100000;
  6 struct Sa{
  7     int sa[N];
  8     int tmr[N];
  9     int rnk[N];
 10     int has[N];
 11     int str[N];
 12     int hgt[N];
 13     int Rmq[20][N];
 14     int lg[N];
 15     int cnt;
 16     int n;
 17     bool Same(int a,int b,int l)
 18     {
 19         if(a+l>n||b+l>n)
 20             return false;
 21         return (rnk[a]==rnk[b])&&(rnk[a+l]==rnk[b+l]);
 22     }
 23     void Insert(int *a,int len)
 24     {
 25         for(int i=1;i<=len;i++)
 26             str[i]=a[i];
 27         n=len;
 28         return ;
 29     }
 30     void Reverse(int *a,int len)
 31     {
 32         int j=0;
 33         for(int i=len;i;i--)
 34             str[++j]=a[i];
 35         n=len;
 36         return ;
 37     }
 38     void Build(void)
 39     {
 40         for(int i=2;i<=n;i++)
 41             lg[i]=lg[i/2]+1;
 42         for(int i=1;i<=n;i++)
 43             has[str[i]]++;
 44         for(int i=1;i<=n;i++)
 45             if(has[i])
 46                 tmr[i]=++cnt;
 47         for(int i=1;i<=n;i++)
 48             has[i]+=has[i-1];
 49         for(int i=1;i<=n;i++)
 50         {
 51             sa[has[str[i]]--]=i;
 52             rnk[i]=tmr[str[i]];
 53         }
 54         for(int k=1;cnt!=n;k<<=1)
 55         {
 56             cnt=0;
 57             for(int i=0;i<=n;i++)
 58                 has[i]=0;
 59             for(int i=1;i<=n;i++)
 60                 has[rnk[i]]++;
 61             for(int i=1;i<=n;i++)
 62                 has[i]+=has[i-1];
 63             for(int i=n;i;i--)
 64                 if(sa[i]>k)
 65                     tmr[sa[i]-k]=has[rnk[sa[i]-k]]--;
 66             for(int i=1;i<=k;i++)
 67                 tmr[n-i+1]=has[rnk[n-i+1]]--;
 68             for(int i=1;i<=n;i++)
 69                 sa[tmr[i]]=i;
 70             for(int i=1;i<=n;i++)
 71                 if(Same(sa[i],sa[i-1],k))
 72                     tmr[sa[i]]=cnt;
 73                 else
 74                     tmr[sa[i]]=++cnt;
 75             for(int i=1;i<=n;i++)
 76                 rnk[i]=tmr[i];
 77         }
 78         for(int i=1;i<=n;i++)
 79         {
 80             if(rnk[i]==1)
 81                 continue;
 82             int j=std::max(1,hgt[rnk[i-1]]-1);
 83             while(str[i+j-1]==str[sa[rnk[i]-1]+j-1])
 84                 hgt[rnk[i]]=j++;
 85         }
 86         for(int i=1;i<=n;i++)
 87             Rmq[0][i]=hgt[i];
 88         for(int i=1;i<=17;i++)
 89             for(int j=1;j+(1<<i)-1<=n;j++)
 90                 Rmq[i][j]=std::min(Rmq[i-1][j],Rmq[i-1][j+(1<<(i-1))]);
 91         return ;
 92     }
 93     int Lcp(int i,int j)
 94     {
 95         i=rnk[i],j=rnk[j];
 96         if(j<i)
 97             i^=j^=i^=j;
 98         i++;
 99         int l=lg[j-i+1];
100         return std::min(Rmq[l][i],Rmq[l][j-(1<<l)+1]);
101     }
102 }S1,S2;
103 int tmp[N];
104 int sln[N];
105 int n,B;
106 std::map<int,int>M;
107 int main()
108 {
109     //freopen("a.in","r",stdin);
110     scanf("%d%d",&n,&B);
111     int cnt=0;
112     for(int i=1;i<=n;i++)
113         scanf("%d",&sln[i]);
114     for(int i=n;i>=2;i--)
115         sln[i]-=sln[i-1];
116     for(int i=2;i<=n;i++)
117     {
118         if(M.find(sln[i])==M.end())
119             M[sln[i]]=++cnt;
120         tmp[i-1]=M[sln[i]];
121     }
122     S1.Insert(tmp,n-1);
123     S2.Reverse(tmp,n-1);
124     S1.Build();
125     S2.Build();
126     int ans=0;
127     for(int L=1;L<=((n-1)-B)/2;L++)
128     {
129         for(int i=1;i<=n-1;i+=L)
130         {
131             int j=i+B+L;
132             if(j>n-1)
133                 continue;
134             int r=std::min(L,S1.Lcp(i,j));
135             int l=std::min(L,S2.Lcp(n-i,n-j));
136             int t=l+r-1;
137             if(t>=L)
138                 ans+=t-L+1;
139         }
140     }
141     printf("%d
",ans);
142     return 0;
143 }
原文地址:https://www.cnblogs.com/blog-Dr-J/p/10046427.html