zoukankan      html  css  js  c++  java
  • 【BZOJ 4516】生成魔咒

    【链接】h在这里写链接


    【题意】


        【Description】
            给你n(n<=10^9)个数字,把它们依次,一个一个地添加在空串S的后面.
            要求每添加一次之后,都要求出串S的本质不同的子串个数。
            即维护字符串的本质不同的子串个数.


    【题解】


        把整个字符串倒过来。
        这样,就变成求从第n-i开始的后缀,它本质不同的子串的个数了。
        我们可以利用前i-1个的答案,对于第i个答案;看看从第n-i开始的后缀会和之前哪些已经算过的
        后缀产生重叠的部分->lcp->则减去lcp就是新增加的子串的个数了。
        (这部分lcp是什么时候算的不重要,反正你只要知道它之前有被算过就好了);
        ->回忆一下求n个字符的不同子串的时候的做法,则我们只要找到已经算过的,和它排名相邻(最靠近)的两个后缀.
        答案+=n-i-max(lcp1,lcp2);
        cout << 答案 << endl;
            n个字符不同子串的时候,只要删掉height[i]就可以了,是因为Rank为i+1的后缀我们还没算,
            (因为我们是顺序i从1..n的)..所以不用考虑Height[i+1])


    【错的次数】


    0

    【反思】


    Tip:前缀问题,倒转一下就能转化为后缀问题了.

    【代码】

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N = 2e5;
    const int MAX_CHAR = 1e5+10;//每个数字的最大值。
    int s[N + 10];//如果是数字,就写成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];
    map <int, int> dic;
    
    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;//数值绝对值的最大值
    int n, tot;
    set <int> mset;
    
    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 main() {
    	//freopen("F:\rush.txt", "r", stdin);
    	scanf("%d", &n);
    	for (int i = 0; i <= n-1; i++) {
    		int x;
    		scanf("%d", &x);
    		if (dic[x] == 0) dic[x] = ++tot;
    		s[n-i-1] = dic[x];
    	}
    	s[n] = 0;
    	build_Sa(n + 1, MAX_CHAR);//注意调用n+1
    	getHeight(n);
    	ST.init(n);
    	ST.getst(Height, n);
    	ll ans = 1;
    	mset.insert(Rank[n - 1]);
    	printf("%lld
    ", ans);
    	for (int i = n - 2; i >= 0; i--)
    	{
    		int mx = 0;
    		set<int>::iterator it = mset.upper_bound(Rank[i]);
    		if (it != mset.end()) mx = max(mx, ST.getmin(Rank[i] + 1, *it));
    		if (it != mset.begin())
    		{
    			it--;
    			mx = max(mx, ST.getmin((*it) + 1, Rank[i]));
    		}
    		ans += n - i - mx;
    		mset.insert(Rank[i]);
    		printf("%lld
    ", ans);
    	}
    	
    	return 0;
    }


  • 相关阅读:
    pgspider sqlite mysql docker 镜像
    pgspider docker 镜像
    pgspider基于pg 的高性能数据可视化sql 集群引擎
    diesel rust orm 框架试用
    golang 条件编译
    Performance Profiling Zeebe
    bazel 学习一 简单java 项目运行
    一个好用node http keeplive agnet
    gox 简单灵活的golang 跨平台编译工具
    mailhog 作为smtp server mock工具
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7625981.html
Copyright © 2011-2022 走看看