【JZOJ6379】小w與密碼(password)

description


analysis

  • 考慮ss的某個前綴aatt的某個前綴bb拼成的一個字符串a+ba+b

  • 如果該字符串可以被另幾種a+ba'+b'拼出來,欽定bb最短的那種只算一次

  • 考慮a0+b0=a1+b1=...=ak+bka_0+b_0=a_1+b_1=...=a_k+b_k,其中b0b_0最短

  • 其中滿足bib_i同時是bi+1b_{i+1}的前綴和後綴,可以畫圖理解

  • 這是因爲每個bb都是tt的前綴,且bib_i也完全是bi+1b_{i+1}的後綴

  • 相當於KMPKMP求得的nextnext的定義,bib_inextnext總指向bi1b_{i-1}的末尾位置

  • 對於tt的前綴,只要該前綴有nextnext,說明這種前綴可以被它指向的nextnext的更短前綴替代

  • 當然前綴還可以被它自己的nextnext不斷替代,直到該前綴沒有nextnext,即不可被替代

  • 建出ttnextnext後,拿sstt上面跑KMPKMP,求出tt每個前綴在ss中出現的次數numnum

  • 具體求就是匹配完把numnum求一次後綴和,相當於所有情況全部集中到沒有nextnext的前綴上,就求出了每個前綴出現次數

  • 然後把答案減掉前綴出現的次數就好了

  • 這題思維難但代碼很短,以後要好好動腦想


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)

using namespace std;

ll next[MAXN],num[MAXN];
char s[MAXN],t[MAXN];
ll n,m,ans;

int main()
{
	//freopen("T2.in","r",stdin);
	freopen("password.in","r",stdin);
	freopen("password.out","w",stdout);
	scanf("%s%s",s+1,t+1),n=strlen(s+1),m=strlen(t+1),ans=n*m;
	for (reg i=2,j=0;i<=m;++i)
	{
		while (j && t[j+1]!=t[i])j=next[j];
		if (t[j+1]==t[i])++j;next[i]=j;
	}
	for (reg i=2,j=0;i<=n;++i)
	{
		while (j && t[j+1]!=s[i])j=next[j];
		if (t[j+1]==s[i])
		{
			++num[++j];
			if (j==m)j=next[j];
		}
	}
	fd(i,n,1)num[next[i]]+=num[i];
	fo(i,1,m)ans-=next[i]?num[i-next[i]]:0;
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章