记录编号 394612 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [HAOI 2016]找相同子串 最终得分 100
用户昵称 Gravatarsxysxy 是否通过 通过
代码语言 C++ 运行时间 1.270 s
提交时间 2017-04-13 19:41:28 内存使用 55.62 MiB
显示代码纯文本
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <algorithm>
#include <list>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 4e5+6;
int len[MAXN], next[MAXN][26], link[MAXN], size[MAXN];
const int root = 1;
int cnt = 1;
int last = 1;
void expand(int c){
	int cur = ++cnt; len[cur] = len[last]+1; size[cur] = 1;
	int p;
	for(p = last; p && !next[p][c]; p = link[p]){
		next[p][c] = cur;	
	}
	if(!p)link[cur] = 1;
	else{
		int q = next[p][c];
		if(len[q] == len[p]+1)link[cur] = q;
		else{
			int clone = ++cnt;
			link[clone] = link[q]; len[clone] = len[p]+1;
			memcpy(next[clone], next[q], sizeof next[0]);
			for(; p && next[p][c] == q; p = link[p])next[p][c] = clone;
			link[cur] = link[q] = clone;
		}
	}
	last = cur;
}
char buf[MAXN];
int rank[MAXN], buk[MAXN];
vector<int> G[MAXN];
typedef long long LL;
LL f[MAXN]; //f[s] 状态s以及它的所有祖先匹配的子串的数量。 
void dfs(int u){
	f[u] += 1ll*size[u]*(len[u]-len[link[u]]); 
	for(int i = 0; i < G[u].size(); i++)
		f[G[u][i]] += f[u], dfs(G[u][i]);
}
int main(){
	freopen("find_2016.in", "r", stdin);
	freopen("find_2016.out", "w", stdout);
  scanf("%s", buf);
	for(int i = 0; buf[i]; i++)expand(buf[i]-'a');
	//topo sort
	for(int i = 1; i <= cnt; i++)buk[len[i]]++;
	for(int i = 1; i <= cnt; i++)buk[i] += buk[i-1];
	for(int i = cnt; i; i--)rank[buk[len[i]]--] = i;
	//这里才完成对size的计算 
	for(int i = cnt; i; i--)size[link[rank[i]]] += size[rank[i]];
	for(int i = 1; i <= cnt; i++)
		if(link[i])G[link[i]].push_back(i); //计算f 
	dfs(1);
	scanf("%s", buf);
	LL ans = 0;
	int st = 1, mlen = 0;
	for(int i = 0; buf[i]; i++){
		int c = buf[i]-'a';
    if(next[st][c]){
      mlen++; 
      st = next[st][c];
    }else{
      while(st && !next[st][c])st = link[st];
      if(!st)st = 1, mlen = 0;
      else mlen = len[st]+1, st = next[st][c];
    } //mlen成为第二个串[0,i]与第一个串的最长公共子串的长度
		ans += f[link[st]]; //当前转移到了状态st,状态st的祖先全都可以匹配 
		ans += 1ll*(mlen-len[link[st]])*size[st]; 
			//状态st本身只匹配了(mlen-len[link[st]])*size[st]个。 
	}
	printf("%lld\n", ans);
	return 0;
}