【HDU 7015 Another String】题解

题目链接

题目

Define the distance between two strings of the same length as the numbers of the positions where the characters differ in these two strings.

If two strings of the same length has a distance of no more than k, we call these two string satisfy k−matching.

Given a string S of length n and a integer k. For each i∈[1,n−1], split S into substrings A and B, while A=S[1,i] and B=S[i+1,n]. For all the string pairs formed by some non empty substring of A and some non empty substrings of B, count the numbers of pairs satisfying k−matching.

给定一个串 \(S\),对于每一个前缀 \(A\) 以及对应的后缀 \(B\),问有多少个子串对之间的距离不超过 K。
两个相同长度的串的距离定义为他们不同字符的个数。

len <= 3000, K <= 3000

思路

\(dp(i, j)\) 表示从 \(i\)\(j\) 开始的前缀中距离不超过 \(K\) 的最长长度。(假设 \(i<j\))

然后我们考虑对答案的贡献。

然后我们会发现有当分割点不同时会有四种状态:

  • A:\([1, i-1]\) 这个时候没有包括 \(i\),贡献为0
  • B:\([i, i+dp(i,j)-1]\) 这个时候包括了 \(i\),且答案会逐渐递增。
  • C:\([i+dp(i, j), j-1]\) 这个时候 \(i\) 在一边,\(j\) 在一边,答案保持为 \(dp(i, j)\)
  • D:\([j, n]\) 这个时候 \(i\)\(j\) 都在分割点的左边,贡献为0

然后我们尝试对答案数组差分

  • A:\([1, i-1]\) 差分为0
  • B:\([i, i+dp(i,j)-1]\) 差分为1
  • C:\([i+dp(i, j), j-1]\) 差分为0
  • j: 差分为 \(-dp(i, j)\)
  • D:\([j+1, n]\) 这个时候 \(i\)\(j\) 差分为0

然后我们再做一次差分:

  • \(i\)\(1\)
  • \(i+dp(i,j)\)\(-1\)
  • \(j\)\(dp(i,j)\)
  • \(j+1\)\(-dp(i,j)\)

然后我们维护二次差分数组,最后统计答案时做两次前缀和即可。

至于 \(dp(i,j)\) 可以用双指针维护,甚至数组也不用开了。

时间复杂度:\(O(n^2)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 3010
int n, m, i, j, k; 
int c[N], cha[N], ans[N]; 
int f, t, l, len, dif; 
char s[N]; 

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	t=read(); 
	while(t--)
	{
		memset(c, 0, sizeof(c)); 
		n=read(); l=read(); 
		scanf("%s", s+1); 
		for(k=1; k<=n; ++k, dif=len=0)
			for(i=1, j=i+k; j<=n; ++i, ++j)
			{
				while(dif<=l) dif+=(s[i+len]!=s[j+len]), ++len; 
				f=min(len-1, min(k, n-j+1)); 
				c[i]+=1; c[i+f]-=1; c[j]-=f; c[j+1]+=f; 
				len--; dif-=(s[i]!=s[j]); 
			}
		for(i=1; i<=n; ++i) cha[i]=cha[i-1]+c[i]; 
		for(i=1; i<=n; ++i) ans[i]=ans[i-1]+cha[i]; 
		for(i=1; i<n; ++i) printf("%lld\n", ans[i]); 
	}
	return 0; 
}

posted @ 2021-12-08 19:01  zhangtingxi  阅读(45)  评论(0编辑  收藏  举报