【2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest C】【脑洞 本质不同实现的转化】Concatenation A串为前缀B串为后缀不同串

#include<stdio.h> 
#include<string.h>
#define MS(x,y) memset(x,y,sizeof(x))
typedef long long LL;
const int N=1e5+10,M=0,Z=1e9+7,ms63=1061109567;
char a[N],b[N];
int c[128];
void fre()
{
	freopen("concatenation.in","r",stdin);
	freopen("concatenation.out","w",stdout);
}
int main()
{
	fre();
	while(~scanf("%s%s",a,b))
	{
		int n=strlen(a);
		int m=strlen(b);
		MS(c,0);LL ans=LL(n)*m;
		for(int i=1;i<n;i++)++c[a[i]];
		for(int i=0;i<m-1;i++)ans-=c[b[i]];
		printf("%lld\n",ans);
	}
	return 0;
}
/*
【trick&&吐槽】
一些题目看起来很难,然而却又积极惊人的性质,可以用很高效的复杂度AC >_<
其实一开始就想到了正解,如果抓住问题多思考,就能解决了,好可惜。

【题意】
 给你两个串a、b,(长度都为[1,1e5]范围)。
 让你从a串取一个非空前缀串,从b串取一个非空后缀串。
 然后把两个串拼起来。问你能拼出多少个本质不同串。

【类型】
脑洞

【分析】
在没有重复串的情况下,本质不同串的个数是n*m,
我们怎么考虑本质相同串呢?
想一想这道题可以怎么把问题转化为数学语言——
这题其实就是,我们枚举a串的结尾节点i∈[0~n-1],枚举b串的开头节点j∈[0~n-1],然后两串合并,看是否重复。
什么时候可能出现串重复呢?对于一个a[i]==b[j],我们可以——
1,以a[i]为结尾,抛弃b[j],不以b[j]为开头
2,不以a[i]为结尾,抛弃a[i],以b[j]为开头,
这两者形成的串是相同的,必然会出现本质不同串的个数+1。

然而这个理解起来有些困难,于是我们拿出一组数据{aaa,aaa},
我们发现会形成{a aaa} {aa aa} {aaa a},共计3个aaaa
而两个串什么时候会重复呢?
对于同一个长度的串,当{第一个串延展长度+1,第二个串延展长度-1}且延展后与延展前串相同时,会产生重复串。
实际上,这个产生重复串的条件,等同于a[i]==b[j]。
于是才有了一开始的做法。
现在也给出了具体的证明。
于是可以用O(n)的时间AC啦。

【时间复杂度&&优化】
O(n)

*/

你可能感兴趣的:(ACM,codeforces,脑洞)