hdu 6068 Classic Quotation

  QAQ http://acm.hdu.edu.cn/showproblem.php?pid=6068

  2017 Multi-University Training Contest - Team 4 - 1005

  贴一张官方题解

  

  其中S可以由O(n*m)的求前缀得到。

  求suf贼难,淦。

  求suf主要是通过类似DP的思想

  其中ismatch[i][j]表示T的匹配指针为i,匹配到字母j的时候,是否新匹配了一个完整的T串。

  nxt2[i][j]表示,当T的匹配指针为i,匹配到字母j的时候,T的指针转移到哪个位置

  然后未求前缀的suf数组就可以倒着DP出来了

  (思路来自某官方题解和某其他博客的题解)

  

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int M=5e4+44;
const int N=244;

int n,m,qur;
char S[M],T[N];
int nxt[N];
int preg[M];
int s[M][N];
int suf[M][N];
int ismatch[N][N],nxt2[N][N];

void init()
{
	int i,j,k,tmp,tmpi,tmpj;

	//get the nxt of T
	nxt[1]=0; k=0;
	for(j=2;j<=m;j++)
	{
		while(k && T[k+1]!=T[j])
			k=nxt[k];
		if(T[k+1]==T[j])
			k++;
		nxt[j]=k;
	}
	
	//get preg,s
	j=0;
	tmp=0;
	memset(s,0,sizeof(s));
	for(i=1;i<=n;i++)
	{
		while(j && T[j+1]!=S[i])
			j=nxt[j];
		if(T[j+1]==S[i])
			j++;
		if(j==m)
		{
			tmp++;
			j=nxt[j];
		}
		preg[i]=tmp; s[i][j]++;
	}
	for(i=2;i<=n;i++)
		for(j=0;j<m;j++)
			s[i][j]+=s[i-1][j];
	for(i=2;i<=n;i++)
		preg[i]+=preg[i-1];
	
	//get suf
	for(i=0;i<m;i++)
		for(j='a';j<='z';j++)
		{
			ismatch[i][j]=0;
			k=i;
			while(k!=0 && T[k+1]!=j)
				k=nxt[k];
			if(T[k+1]==j)
				k++;
			if(k==m)
			{
				ismatch[i][j]=1;
				k=nxt[k];
			}
			nxt2[i][j]=k;
		}
	for(i=0;i<m;i++)
		suf[n+1][i]=0;
	for(i=n;i>=1;i--)
		for(j=0;j<m;j++)
			suf[i][j]=ismatch[j][S[i]]+suf[i+1][nxt2[j][S[i]]];
	for(i=n;i>=1;i--)
		for(j=0;j<m;j++)
			suf[i][j]+=suf[i+1][j];
}

void solve()
{
	int i,j,L,R;
	ll ans;
	while(qur--)
	{
		scanf("%d%d",&L,&R);
		ans=1ll*(n-R+1)*preg[L];
		for(i=0;i<m;i++)
			ans+=1ll*s[L][i]*suf[R][i];
		printf("%lld
",ans);
	}
}

int main()
{
	int i,j,cas;
	scanf("%d",&cas);
	while(cas--)
	{
		scanf("%d%d%d",&n,&m,&qur);
		scanf("%s%s",S+1,T+1);
		init();
		solve();
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/FxxL/p/7291040.html