J - Life Forms POJ - 3294

后缀数组加上二分。(其实单调栈也行,二分也是因为其单调性)
首先,我们如果利用two pointers的思想来看,从lf出发,rt不断往前面跳转,公共子串长度为min lcp(lf,rt),当且仅当lf到rt之间,字串出现在了n/2个主串时候停止。
那么这个时候如果rt再往下走,依然满足题意,但同时,因为求的是最长字串,我们往下走取得是min(lcp(lf,rt))所以对于答案来说,不会有正向收益。
这就是我们二分的来源。我们以次二分,枚举最长公共子串的长度len,暴力判断是否满足题意,因为我们二分的长度,所以就不用考虑min lcp带来的影响,只用考虑是否满足n/2,所以我们这里贪心的匹配,尽力做到满足即可。
对于长度一定,可能有多个字符串的时候,在同一个分区里面,结果是一样的,不同分区里面,单独计算即可。(后缀数组已经按照字典序排列)
坑点:不能用#分割字符串,因为有至多100个字符串,那么就可能会有#这个字符串被匹配进来。应该开int数组来解决。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int rk[N], height[N], sa[N], t[N], t2[N], c[N];
int s[N];
string ts;
int n;
int T;
int limited;
int index[N];
int vis[105];
int ans[N];
void da() {
	int *x = t;
	int *y = t2;
	int m = 330;
	up(i, 0, m)c[i] = 0;
	up(i, 0, n)c[x[i] = s[i]]++;
	up(i, 1, m)c[i] += c[i - 1];
	dwd(i, n - 1, 0)sa[--c[x[i]]] = i;
	for (int k = 1; k <= n; k <<= 1)
	{
		int p = 0;
		up(i, n - k, n)y[p++] = i;
		up(i, 0, n)if (sa[i] >= k)y[p++] = sa[i] - k;
		up(i, 0, m)c[i] = 0;
		up(i, 0, n)c[x[y[i]]]++;
		up(i, 1, m)c[i] += c[i - 1];
		dwd(i, n - 1, 0)sa[--c[x[y[i]]]] = y[i];
		swap(x, y);
		p = 1;
		x[sa[0]] = 0;
		up(i, 1, n)
			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() {
	up(i, 0, n)
		rk[sa[i]] = i;
	int j = 0;
	int k = 0;
	up(i, 0, n)
	{
		if (k)k--;
		j = sa[rk[i] - 1];
		while (s[i + k] == s[j + k])k++;
		height[rk[i]] = k;
	}
}
void test()
{
	cout << "suffix:" << endl;
	up(i, 0, n)
	{
		//cout << "sa" << sa[i] << endl;
		up(j, sa[i], n)cout << s[j] << " ";
		cout << endl;
		cout << height[i] << endl;
	}
}
bool judge(int len)
{
	memset(vis, 0, sizeof(vis));
	int num = 0;
	int now = 0;
	up(i, 1, n)
	{
		if (height[i] >= len && s[sa[i]] != '#')
		{
			num += vis[index[sa[i]]] ? 0 : 1;
			vis[index[sa[i]]] = 1;
			num += vis[index[sa[i - 1]]] ? 0 : 1;
			vis[index[sa[i - 1]]] = 1;
		}
		else
		{
			if (num > limited)ans[now++] = sa[i - 1];
			memset(vis, 0, sizeof(vis));
			num = 0;
		}
	}
	if (num > limited)ans[now++] = sa[n - 1];
	if (now)
	{
		ans[now] = -1;
		return 1;
	}
	else { return 0; }
}
void work()
{
	int lf = -1, rt = n;
	memset(ans, -1, sizeof(ans));
	while (rt > lf + 1)
	{
		int mid = (lf + rt) / 2;
		if (judge(mid))lf = mid;
		else rt = mid;
	}
	if (lf == 0)cout << "?" << endl;
	else {
		for (int i = 0; ans[i] != -1; i++)
		{
			up(j, 0, lf)
			{
				cout << (char)s[ans[i] + j];
			}
			cout << endl;
		}
	}
	cout << endl;
}

int main()
{
	ios::sync_with_stdio(false);
	while (scanf("%d", &T) && T)
	{
		int cnt = 0;
		up(i,0,T)
		{
			cin >> ts;
			for (int j=0;j<ts.size();j++)
			{
				s[cnt] = ts[j];
				index[cnt++] = i;
			}
			s[cnt] = 150 + i;
			index[cnt++] = i;
		}
		s[cnt] = 30;
		index[cnt++] = T;
	//	cout << s;
		n = cnt;
		da();
		//test();
		getheight();
		limited = T / 2;
		work();
	}
}
posted @ 2019-12-05 22:15  LORDXX  阅读(211)  评论(0编辑  收藏  举报