1. 程式人生 > >SPOJ 220 Relevant Phrases of Annihilation(每個字串至少出現兩次且不重疊的最長子串)

SPOJ 220 Relevant Phrases of Annihilation(每個字串至少出現兩次且不重疊的最長子串)

題目:給定n個字串,求出每個字串至少出現兩次且不重疊的最長子串 

將n個字串連線起來,中間用不同的特殊字元隔開。求出字尾陣列

二分答案,通過height值將字尾分組,判斷在每一組中,每個字串是否至少出現兩次

而且由於題目需要不重疊的子串,所以還要記錄每個字串位置的最大值和最小值

判斷其差是否小於當前答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100005
#define LL long long
#define maxn 200005
#define inf 1<<30
using namespace std;
//以下為倍增演算法求字尾陣列  
int wa[maxn],wb[maxn],wv[maxn],Ws[maxn];  
int cmp(int *r,int a,int b,int l)  
{return r[a]==r[b]&&r[a+l]==r[b+l];}  
void da(const int *r,int *sa,int n,int m){  
	int i,j,p,*x=wa,*y=wb,*t;   
	for(i=0;i<m;i++) Ws[i]=0;   
	for(i=0;i<n;i++) Ws[x[i]=r[i]]++;   
	for(i=1;i<m;i++) Ws[i]+=Ws[i-1];   
	for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i;   
	for(j=1,p=1;p<n;j*=2,m=p){   
		for(p=0,i=n-j;i<n;i++) y[p++]=i;   
		for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;   
		for(i=0;i<n;i++) wv[i]=x[y[i]];   
		for(i=0;i<m;i++) Ws[i]=0;   
		for(i=0;i<n;i++) Ws[wv[i]]++;   
		for(i=1;i<m;i++) Ws[i]+=Ws[i-1];   
		for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];   
		for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)   
			x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;   
	}   
	return;   
}  
int sa[maxn],Rank[maxn],height[maxn];  
//求height陣列  
void calheight(const int *r,int *sa,int n){  
	int i,j,k=0;  
	for(i=1;i<=n;i++) Rank[sa[i]]=i;  
	for(i=0;i<n;height[Rank[i++]]=k)  
		for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);  
	return;  
}
char ch[maxn];
int str[maxn];
int l[105];
int mx[15],mn[15];
int in[maxn];
int k;
bool check(int mid,int n){
	for(int i=0;i<k;i++){mx[i]=0;mn[i]=inf;} 
	for(int i=1;i<=n;i++){
		if(height[i]<mid){
			for(int i=0;i<k;i++){
				mx[i]=0;
				mn[i]=inf;
			}
			mx[in[sa[i]]]=sa[i];
			mn[in[sa[i]]]=sa[i];
		}
		else{
			mx[in[sa[i]]]=max(mx[in[sa[i]]],sa[i]);
			mn[in[sa[i]]]=min(mn[in[sa[i]]],sa[i]);
			mx[in[sa[i-1]]]=max(mx[in[sa[i-1]]],sa[i-1]);
			mn[in[sa[i-1]]]=min(mn[in[sa[i-1]]],sa[i-1]);
			int j;
			for(j=0;j<k;j++){
				if(mx[j]-mn[j]<mid)
					break;
			}
			if(j==k) return true;
		}
	}
	return false;
}
int main(){
	int cnt=0,t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&k);
		int n=0;
		for(int i=0;i<k;i++){
			scanf("%s",ch);
			l[i]=strlen(ch);
			for(int j=n;j<n+l[i];j++){
				str[j]=ch[j-n]-'a'+1;
				in[j]=i;
			}
			n+=l[i]+1;
			str[n-1]=27+i;
		}
		n--;
		str[n]=0;
		da(str,sa,n+1,27+k+5);
		calheight(str,sa,n);
		int low=0,high=10000,mid,ans=0;
		while(low<=high){
			mid=(low+high)/2;
			if(check(mid,n)){ans=mid;low=mid+1;}
			else high=mid-1;
		}
		printf("%d\n",ans);
	}
	return 0;
}


相關推薦

SPOJ 220 Relevant Phrases of Annihilation每個字串至少出現重疊長子

題目:給定n個字串,求出每個字串至少出現兩次且不重疊的最長子串  將n個字串連線起來,中間用不同的特殊字元隔開。求出字尾陣列 二分答案,通過height值將字尾分組,判斷在每一組中,每個字串是否至少出現兩次 而且由於題目需要不重疊的子串,所以還要記錄每個字串位置的最大值

SPOJ PHRASES 每個字串至少出現重疊長子

You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages concerning the date of the planned attack on your isla

每個字符至少出現重疊長子

href div title eight mes 。。 scan truct oid Relevant Phrases of Annihilation SPOJ - PHRASES https://cn.vjudge.net/problem/SPOJ-PHRASES 呵。

SPOJ 220. Relevant Phrases of Annihilation(字尾陣列多重疊)

題目大意:給定N個串,求每個串至少出現兩次的最長子串。 解題思路:每個字串至少出現兩次且不可重疊的最長子串:二分列舉長度後在同一分組中對每一個字串保留一個最小的位置和一個最大的位置,最後檢視是否每個串在同一組中都有至少兩個字尾,並且字尾的座標差大於列舉的長度。 POJ P

【SPOJ220】Relevant Phrases of Annihilation後綴數組,二分

spa std spoj lse map sign math vector mod 題意: n<=10,len<=1e4 思路: 1 #include<cstdio> 2 #include<cstring> 3 #incl

2018.11.30 spoj220 Relevant Phrases of Annihilation字尾陣列+二分答案

傳送門 程式碼: 先用特殊字元把所有字串連線在一起。 然後二分答案將 s a sa

2018.12.01【SPOJ220】Relevant Phrases of Annihilation字尾陣列二分答案

傳送門 解析: 套路題。 首先串成一串求一下SA。 然後按照二分出的 l e n

【字尾陣列】【spoj 220Relevant Phrases of Annihilation

基本應用——每個字串至少出現兩次且不重複的最長子串 memset的mmin[]和mmax開大了簡直是作死,狂T不止。。。 //#define _TEST _TEST #include <cstdio> #include <cstring>

演算法程式設計-求陣列中和為0的長子非連續長子+連續長子

輸入:int 型陣列由正數、負數、0組成 輸出:最長和為0的子序列 分析: 1)連續子串 2)非連續子串 void findTargetLen1(vector<int>nums,int sum,int len,int& maxLen,int st

資料結構——演算法之032中的第一個長子

【申明:本文僅限於自我歸納總結和相互交流,有紕漏還望各位指出。 聯絡郵箱:[email protected]】 題目: 求兩個串中的第一個最長子串(神州數碼以前試題).如"abractyeyt","dgdsaeactyey"的最大子串為"actyey".題目

leecode第三題無重復字符的長子

inf push_back 檢測 com lee 比較 pub png 記錄 class Solution { public: int lengthOfLongestSubstring(string s) { int len=s.siz

SPOJ】NUMOFPAL - Number of PalindromesManacher,回文樹

spa cstring stream char define tdi () .so code 【SPOJ】NUMOFPAL - Number of Palindromes(Manacher,回文樹) 題面 洛谷 求一個串中包含幾個回文串 題解 Manacher傻逼題 只是用

雜湊-poj2406每個字串小週期的個數

先建立字串的雜湊陣列 列舉每個子串 ******************************************************************** 建立基數陣列 函式 void fbase() { base[0]=1; for

hdu 6273 Master of GCD線段樹區間維護小值

Hakase has n numbers in a line. At first, they are all equal to 1. Besides, Hakase is interested inprimes. She will choose a continuous su

Spring3 Schedule Task之註解實現 起動Schedule Task 的解決方案

什麽 empty task 文件中 註解 work lin schedule ask Spring3 Schedule Task之註解實現 (兩次起步Schedule Task 的解決方案)Spring3 Schedule Task之註解實現 (兩次啟動Schedule T

代碼題56長重復子、無重復字符的長子

cto wke 新的 pan pty shm 指針數組 map hashmap 1、最長的重復子串   尋找一個字符串中最長的重復子串   最大後綴方法思路: 1. 用字符串指針數組保存用戶輸入的字符串的所有後綴字符串; 2. 將後綴字符串集合進行排序; 3. 比較相鄰字符

FZU - 2128 長子KMP?

問題很簡單,給你一個字串s,問s的子串中不包含s1,s2...sn的最長串有多長。 Input 輸入包含多組資料。第一行為字串s,字串s的長度1到10^6次方,第二行是字串s不能包含的子串個數n,n<=1000。接下來n行字串,長度不大於100。 字串由小

Dijkstra從一個源點到其他各點的短路徑

#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef struct { int vertex[MAXSIZE]; int edges[MAXSIZE][MAXSIZE]; }Gra

leetcode 3. 無重複字元的長子 python語言

class Solution: def lengthOfLongestSubstring(self, s): “”" :type s: str :rtype: int “”" # s為空時返回0 if not s: return 0 # 非空字串的長度最小為1 long = 1 # 子串

python學習小總結列表、元組、字典、集合、字符

添加列 xtend 16px 指定 替換 需要 isa utf-8 head ---恢復內容開始--- 一、列表(list) 1.添加 append():追加,在列表末尾添加元素。 列表名.append(添加的元素) extend():擴展,在列表末尾添加元素。 列表名.e