列表

详情


NC15160. 小H和遗迹

描述

    小H在一片遗迹中发现了一种古老而神秘的文字,这种文字也由26种字母组成,小H用小写字母来代替它们。遗迹里总共有N句话,由于年代久远,每句话至少有一处无法辨识,用#表示,缺失的可能是任意长度(也包括0)的任意字符串。
    小H发现这些话非常相似,现在小H想知道,有多少对句子可能是相同的
    注意:(x,x)这样的句子对不计入答案,(x,y),(y,x)视为同一个句子对(详见样例)

输入描述

第1行,一个整数N
第2~N+1行,每行一个字符串表示一句话
2≤N≤500,000,所有字符串的总长不超过1,000,000

输出描述

一行,一个整数,表示你给出的答案

示例1

输入:

2 
a#a 
#

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 206ms, 内存消耗: 86624K, 提交时间: 2018-02-23 21:26:14

#include <bits/stdc++.h>
using namespace std;

typedef long long  LL;
const int N=1000010;
int n,tot,prt,srt,pre[N],suf[N],ch[N][26],L[N],R[N],t1[N],t2[N];
LL ans;
char s[N];
vector <int> tag[N];

void modify(int *t,int x,int k){for (; x<N; t[x]+=k,x+=x&-x);}
int ask(int *t,int x){int s=0;  for (; x; s+=t[x],x-=x&-x);  return s;}

int insert(int x)
{
	for (int i=1; s[i]!='#'; i++)
		{
			if (!ch[x][s[i]-'a'])  ch[x][s[i]-'a']=++tot;
			x=ch[x][s[i]-'a'];
		}
	return x;
}

void dfs1(int x)
{
	L[x]=++tot;
	for (int i=0; i<26; i++)
		if (ch[x][i])  dfs1(ch[x][i]);
	R[x]=tot;
}

void ask(int i)
{
	i=pre[i];
	ans+=ask(t1,L[i])+ask(t2,R[i])-ask(t2,L[i]);
}

void mark(int i,int k)
{
	i=pre[i];
	modify(t1,L[i],k),modify(t1,R[i]+1,-k),modify(t2,L[i],k);
}

void dfs2(int x)
{
	for (int i=0; i<tag[x].size(); i++)  ask(tag[x][i]),mark(tag[x][i],1);
	for (int i=0; i<26; i++)
		if (ch[x][i])  dfs2(ch[x][i]);
	for (int i=0; i<tag[x].size(); i++)  mark(tag[x][i],-1);
}

void work()
{
	scanf("%d",&n),prt=1,srt=2,tot=2;
	for (int i=1; i<=n; i++)
		{
			scanf("%s",s+1),pre[i]=insert(prt);
			reverse(s+1,s+strlen(s+1)+1),suf[i]=insert(srt);
			tag[pre[i]].push_back(i),tag[suf[i]].push_back(i);
		}
	tot=0;
	dfs1(prt);
	dfs2(srt);
	printf("%lld\n",ans);	
}

int main()
{
	work();
	return 0;
}

上一题