zoukankan      html  css  js  c++  java
  • 【POJ 3294】Life Forms

    【链接】h在这里写链接


    【题意】


    给你n个字符串。
    让你找最长的字符串s;
    这个s在超过一半的子串里面都有出现过且长度大于n/2;
    如果有多个,输出多行。
    (按字典序输出)
    也没说会不会出现大写。




    【题解】


    后缀数组+二分。

    把每个字符串之间用一个没出现过的分隔符分开;
    (从'z'+1开始)

    100*1000 + 100
    大概10万多的样子,设置成15万就好

    长度越大,肯定是越不可能出现的。
    有单调性的。
    l = 2,r = 1000,temp = 0;
    while (l <= r)...
    连续的大于等于二分的长度的Height组
    看看Sa值是不是把n/2 + 1个以上的覆盖到了。
    (用set就好)

    注意答案为1的时候的二分;



    【错的次数】


    0

    【反思】


    在这了写反思

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <set>
    using namespace std;
    
    const int N = 15e4;
    const int MAX_CHAR = 1000;//每个数字的最大值。
    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];
    
    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 = 1000;
    int n,len,idx[N+10];
    char S[MAXL + 10];
    
    bool ok(int l)
    {
    	//找同一组大于等于l的
    	set <int> mset;
    	mset.clear();
    	for (int i = 2; i <= len; i++)//枚举排名第i的后缀
    		if (Height[i]>=l)
    		{
    			mset.insert(idx[Sa[i - 1]]), mset.insert(idx[Sa[i]]);//
    		}
    		else
    		{
    			if ((int)mset.size() >= n / 2 + 1) return true;
    			mset.clear();
    		}
    	if ((int)mset.size() >= n / 2 + 1) return true;
    	return false;
    }
    
    void out(int l)
    {
    	set <int> mset;//模拟之前的过程再做一遍就好
    	mset.clear();
    	for (int i = 2; i <= len; i++)//枚举排名第i的后缀
    		if (Height[i] >= l)
    		{
    			mset.insert(idx[Sa[i - 1]]), mset.insert(idx[Sa[i]]);//
    		}
    		else
    		{
    			if ((int)mset.size() >= n / 2 + 1)
    			{
    				for (int j = Sa[i - 1]; j <= Sa[i - 1] + l - 1; j++)
    					putchar((char)s[j]);
    				puts("");
    			}
    			mset.clear();
    		}
    	//不可能为0
    }
    
    int main() {
    	//freopen("F:\rush.txt", "r", stdin);
    	while (~scanf("%d", &n) && n>0)
    	{
    		len = 0;int  ls;
    		for (int i = 1; i <= n; i++)
    		{
    			scanf("%s", S);
    			ls = strlen(S);
    			for (int j = 0; j < ls; j++) {
    				idx[len] = i;
    				s[len++] = S[j];
    			}
    			idx[len] = i;
    			s[len++] = i + 'z';
    		}
    		s[len] = 0;
    		build_Sa(len + 1, MAX_CHAR);
    		getHeight(len);
    		//开始二分最后的答案的长度
    		int l = 1, r = MAXL, temp = 0;
    		while (l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if (ok(mid))
    			{
    				temp = mid;
    				l = mid + 1;
    			}
    			else
    			{
    				r = mid - 1;
    			}
    		}
    		if (temp == 0)
    			puts("?");
    		else
    			out(temp);
    		puts("");
    	}
    	return 0;
    }
    


  • 相关阅读:
    排球计分的完善
    排球计分(总结)
    排球计分(八)用户注册、验证
    排球计分(七)看一下运行结果
    排球计分(六)view的实现
    排球计分(五)Controller的实现
    排球计分(四)Model的实现
    排球计分(三)架构概要设计
    排球计分(二)需求分析和数据库设计
    排球计分程序重构(六)
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7625991.html
Copyright © 2011-2022 走看看