zoukankan      html  css  js  c++  java
  • 【BZOJ 2119】股市的预测

    【链接】h在这里写链接


    【题意】


        给你一个长度为n的数组a[]
        设b[i] = a[i+1]-a[i];
        然后让你在b[i]里面找ABA的形式。
        这里B的长度要求为m;
        然后让你找这样的连续段的个数。
        n<=10^5,1<=m<=10


    【题解】


        枚举A的长度i;
        然后把长度为N的数组分成i份i份的。
        即1..i,i+1..2i,2i+1..3i..
            关键点->i,2i,3i
            枚举每一个关键点->x
                然后获取x+m+i设为y

                则有:
                    x,x+1,...x+m,x+m+1..x+m+i
                    x                     y
                然后,让x和y同时往左走,设长度为len1.
                让x和y同时往右走,设长度为len2.
                (走的时候要时刻保持s[x]==s[y])
                如果len1+len2>=i,则对答案的贡献为len1+len2-i+1;
                向左向右扩展都不要超过x。这样才不会重复计数。
                只要获取x和x+m+i的lcp,就能得到len2;
                把整个字符串倒过来,再求n-x+1和n-(x+m+i)+1的后缀,就能得到len1了.
                可以一开始就把倒着的和顺着的用一个连接符连成一个字符串.

                枚举A的长度,然后在过程里面做对应答案的就好。
                需要写一个离散化。


    【错的次数】


    0

    【反思】


    最长公共前缀,把字符串倒一下就是求后缀啦

    【代码】

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N = 1e5 + 100;
    const int MAX_CHAR = 5e4 + 100;//每个数字的最大值。
    int s[N + 10],n,m;//如果是数字,就写成int s[N+10]就好,从0开始存
    int Sa[N + 10], T1[N + 10], T2[N + 10], C[N+10];
    int Height[N + 10], Rank[N + 10];
    vector <int> v;
    
    void build_Sa(int n, int m) {
    	int i, *x = T1, *y = T2;
    	for (i = 0; i<m; i++) C[i] = 0;
    	for (i = 0; i<n; i++) C[x[i] = s[i]]++;
    	for (i = 1; i<m; i++) C[i] += C[i - 1];
    	for (i = n - 1; i >= 0; i--) Sa[--C[x[i]]] = i;
    	for (int k = 1; k <= n; k <<= 1)
    	{
    		int p = 0;
    		for (i = n - k; i<n; i++) y[p++] = i;
    		for (i = 0; i<n; i++) if (Sa[i] >= k) y[p++] = Sa[i] - k;
    		for (i = 0; i<m; i++) C[i] = 0;
    		for (i = 0; i<n; i++) C[x[y[i]]]++;
    		for (i = 1; i<m; i++) C[i] += C[i - 1];
    		for (i = n - 1; i >= 0; i--) Sa[--C[x[y[i]]]] = y[i];
    		swap(x, y);
    		p = 1; x[Sa[0]] = 0;
    		for (i = 1; i<n; i++)
    			x[Sa[i]] = y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + k] == y[Sa[i] + k] ? p - 1 : p++;
    		if (p >= n) break;
    		m = p;
    	}
    }
    
    void getHeight(int n)
    {
    	int i, j, k = 0;
    	for (i = 1; i <= n; i++) Rank[Sa[i]] = i;
    	for (i = 0; i<n; i++) {
    		if (k) k--;
    		j = Sa[Rank[i] - 1];
    		while (s[i + k] == s[j + k]) k++;
    		Height[Rank[i]] = k;
    	}
    }
    
    const int MAXL = 18;//log2数组的最大长度
    const int INF = 0x3f3f3f3f;//数值绝对值的最大值
    
    struct abc{
        int pre2[MAXL+5],need[N+10];
        int fmax[N+10][MAXL+5],fmin[N+10][MAXL+5];
    
        void init(int n)
        {
            pre2[0] = 1;
            for (int i = 1;i <= MAXL;i++)
            {
                pre2[i] = pre2[i-1]<<1;
            }
            need[1] = 0; need[2] = 1;
            int temp = 2;
            for (int i = 3; i <= n; i++)//need[i]表示长度为i是2的多少次方,可以理解为[log2i]
                if (pre2[temp] == i)
                    need[i] = need[i - 1] + 1, temp++;
                else
                    need[i] = need[i - 1];
        }
    
        void getst(int *a,int n)
        {
            memset(fmax,-INF,sizeof fmax);
            memset(fmin,INF,sizeof fmin);
            for (int i = 1;i <= n;i++)//下标从0开始就改成对应的就好
                fmax[i][0] = fmin[i][0] = a[i];
    
            for (int l = 1;pre2[l]<=n;l++)
                for (int i = 1;i <= n;i++)
                    if (i+pre2[l]-1<=n)
                        fmax[i][l] = max(fmax[i][l-1],fmax[i+pre2[l-1]][l-1]);
    
            for (int l = 1;pre2[l]<=n;l++)
                for (int i = 1;i <= n;i++)
                    if (i+pre2[l]-1<=n)
                        fmin[i][l] = min(fmin[i][l-1],fmin[i+pre2[l-1]][l-1]);
        }
    
        int getmin(int l,int r)
        {
            int len = need[r-l+1];
            return min(fmin[l][len],fmin[r-pre2[len]+1][len]);
        }
    
        int getmax(int l,int r)
        {
            int len = need[r-l+1];
            return max(fmax[l][len],fmax[r-pre2[len]+1][len]);
        }
    
    }ST;
    
    int lcp(int x,int y)
    {
        return ST.getmin(x+1,y);
    }
    
    ll ans;
    
    void solve(int L)
    {
        for (int x = L-1;x + m + L <n;x+=L)
        {
            int y = x + m + L;
            int len1 = lcp(min(Rank[x],Rank[y]),max(Rank[x],Rank[y]));
            //往右走的lcp
            len1 = min(len1,L);
    
            int len2 = lcp(min(Rank[2*n-x],Rank[2*n-(x+m+L)]),max(Rank[2*n-x],Rank[2*n-(x+m+L)]));
            len2 = min(len2,L);
            //往左走的LCp
    
            int temp = len1+len2;
            if (len1>0 && len2 > 0) temp--;
            if (temp >= L)
            {
                ans += temp-L+1;
            }
        }
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for (int i = 0;i <= n-1;i++) scanf("%d",&s[i]);
        n--;
        for (int i = 0;i <= n-1;i++){
            s[i] = s[i+1]-s[i];
            v.push_back(s[i]);
        }
        sort(v.begin(),v.end());
        for (int i = 0;i < n;i++)
            s[i] = lower_bound(v.begin(),v.end(),s[i]) - v.begin() + 1;
        s[n] = 5e4 + 1;
        int temp = n-1;//temp指向输入的最后一个数字
        //总的长度为n*2 + 1 最后一个数字的位置就是2*n
        for (int i = n+1;temp>=0;i++) {
                s[i] = s[temp--];
        }
        s[2*n+1] = 0;
    
        build_Sa(2*n + 1 + 1,MAX_CHAR);
        getHeight(2*n+1);
        ST.init(2*n+1);
        ST.getst(Height,2*n+1);
    
        for (int i = 1;i-1+m+i < n;i++)//枚举A的长度
            solve(i);
        printf("%lld
    ",ans);
        return 0;
    }
    


  • 相关阅读:
    C#操作OFFICE一(EXCEL)
    json的使用二(转)
    xpath简介(转载)
    使用LogParser分析IIS网站日志
    WCF Data Contract KnownTypeAttribute转载
    ExtJs中同一个URL构造多个Ext.data.JsonStore 转载
    转载Ext.form.formPanel 与服务器交互 初始化表单
    oracle表数据误删恢复
    JavaScript基础之Array函数
    Json格式类的转换相关代码转载
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7625978.html
Copyright © 2011-2022 走看看