1. 程式人生 > 遊戲 >《雙點醫院》開發商新作《雙點大學》洩露 登陸主機和PC

《雙點醫院》開發商新作《雙點大學》洩露 登陸主機和PC

考慮先把\(SAM\)建出來。
然後考慮怎麼統計答案。

首先考慮每個等價類,如果他沒有兒子的話,那麼他必定只出現了一次。而對於不是葉子節點的等價類,該等價類出現的次數為兒子出現次數的和。

那麼我們只要在link樹上\(dfs\)就行了,考慮每個等價類內挑最長的子串長度即\(len_u\)來計入答案。

【模板】字尾自動機 (SAM)
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll int
#define N 1000005
#define fa link

ll ch[N << 1][30];//tire樹的轉移
ll link[N << 1],len[N << 1],v[N << 1];

ll node = 1,lst = 1;

ll cnt,head[N << 1];
struct P{int to,next;}e[N << 1];

inline void insert(int c){
	int p = lst,q = ++node;lst = q;
	len[q] = len[p] + 1,v[q] = 1;
	while(!ch[p][c] && p != 0){//向上找 
		ch[p][c] = q;
		p = link[p];
	} 
	if(p == 0)
	link[q] = 1;
	else{
		int x = ch[p][c];
		if(len[p] + 1 == len[x]){
			link[q] = x;
		}else{
			int y = ++ node ;//複製一個新節點
			link[y] = link[x];
			link[x] = link[q] = y;
			len[y] = len[p] + 1;
			std::memcpy(ch[y],ch[x],sizeof(ch[x])); 
			while(p != 0 && ch[p][c] == x){
				ch[p][c] = y;
				p = link[p];
			}
		}
	}
}

inline void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

char s[N];
ll ans;

inline void dfs(int u){
	if(head[u] == 0)
	v[u] = 1;
	else{
	for(int i = head[u];i;i = e[i].next){
	dfs(e[i].to);
	v[u] += v[e[i].to];
	}
	ans = std::max(ans,len[u] * v[u]);
	}
}

int main(){
	freopen("q.in","r",stdin);
	freopen("q.out","w",stdout);
	scanf("%s",s + 1);
	ll l = std::strlen(s + 1);
	for(int i = 1;i <= l;++i)
	insert(s[i] - 'a');
	for(int i = 1;i <= node;++i)
	add(link[i],i);
	dfs(1);
	std::cout<<ans<<std::endl;
}