KMP-MUH and Cube Walls-CodeForces - 471D
题意:
给 定 长 度 为 n 的 整 数 序 列 a 和 长 度 为 m 的 整 数 序 列 b , 其 中 b 序 列 可 以 将 所 有 数 同 时 增 加 或 减 少 h , 问 在 可 以 修 改 b 的 情 况 下 , 序 列 b 在 a 中 最 多 能 够 匹 配 成 功 几 次 。 给定长度为n的整数序列a和长度为m的整数序列b,其中b序列可以将所有数同时增加或减少h,\\问在可以修改b的情况下,序列b在a中最多能够匹配成功几次。 给定长度为n的整数序列a和长度为m的整数序列b,其中b序列可以将所有数同时增加或减少h,问在可以修改b的情况下,序列b在a中最多能够匹配成功几次。
输入输出:
如 样 例 : 将 序 列 b 同 时 增 加 1 得 到 : 4 5 5 4 3 , 与 序 列 a 第 二 个 位 置 起 的 子 串 成 功 匹 配 。 将 序 列 b 同 时 减 少 1 得 到 : 2 3 3 2 1 , 与 序 列 a 的 长 度 为 5 的 后 缀 成 功 匹 配 。 因 此 共 成 功 匹 配 两 次 。 如样例:将序列b同时增加1得到:4\ 5\ 5\ 4\ 3,与序列a第二个位置起的子串成功匹配。\\ \qquad \qquad 将序列b同时减少1得到:2 \ 3 \ 3 \ 2 \ 1,与序列a的长度为5的后缀成功匹配。\\因此共成功匹配两次。 如样例:将序列b同时增加1得到:4 5 5 4 3,与序列a第二个位置起的子串成功匹配。将序列b同时减少1得到:2 3 3 2 1,与序列a的长度为5的后缀成功匹配。因此共成功匹配两次。
题解:
序 列 匹 配 问 题 , 考 虑 K M P 算 法 。 序列匹配问题,考虑KMP算法。 序列匹配问题,考虑KMP算法。
事 实 上 , 无 论 序 列 b 同 时 增 加 或 减 少 多 少 , 相 邻 两 个 数 的 差 是 不 会 改 变 的 。 因 此 , 我 们 只 需 要 将 序 列 a 和 b 差 分 一 次 , 再 去 匹 配 它 们 的 差 分 数 组 即 可 。 事实上,无论序列b同时增加或减少多少,相邻两个数的差是不会改变的。\\因此,我们只需要将序列a和b差分一次,再去匹配它们的差分数组即可。 事实上,无论序列b同时增加或减少多少,相邻两个数的差是不会改变的。因此,我们只需要将序列a和b差分一次,再去匹配它们的差分数组即可。
注意:
差 分 数 组 的 长 度 比 原 数 组 的 长 度 小 1 。 差分数组的长度比原数组的长度小1。 差分数组的长度比原数组的长度小1。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define ll long long
#define inf 0x7fffffff
using namespace std;
const int N=2e5+10;
int Next[N],n,m;
int a[N],b[N];
int da[N],db[N];
void get_next()
{
for(int i=2,j=0;i<m;i++)
{
while(j&&db[i]!=db[j+1]) j=Next[j];
if(db[i]==db[j+1]) j++;
Next[i]=j;
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
if(m==1) {cout<<n<<endl;return 0;}
for(int i=1;i<n;i++) da[i]=a[i+1]-a[i];
for(int i=1;i<m;i++) db[i]=b[i+1]-b[i];
get_next();
int cnt=0;
for(int i=1,j=0;i<n;i++)
{
while(j&&da[i]!=db[j+1]) j=Next[j];
if(da[i]==db[j+1]) j++;
if(j==m-1)
{
cnt++;
j=Next[j];
}
}
printf("%d\n",cnt);
return 0;
}