题意
给你两个数组, 和,长度分别为和,然你求中长度为的子数组,这个子数组,满足
问你有多少个这样的子数组
思路
我们可以把上面的等式拆解下
...
然后左右移项
...
那么求个差分数组,就可以用kmp来匹配了
但是要注意的异号求余,是让商尽量大,所以得
注意相减的取模,把相减的取模转换成正数
代码
/**
* author: andif
* created: 12.06.2023 22:50:58
**/
#include<bits/stdc++.h>
using namespace std;
#define de(x) cerr << #x << " = " << x << endl
#define dd(x) cerr << #x << " = " << x << " "
#define rep(i, a, b) for(int i = a; i < b; ++i)
#define per(i, a, b) for(int i = a; i > b; --i)
#define mt(a, b) memset(a, b, sizeof(a))
#define sz(a) (int)a.size()
#define fi first
#define se second
#define qc ios_base::sync_with_stdio(0);cin.tie(0)
#define eb emplace_back
#define all(a) a.begin(), a.end()
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
vi get_next(const vi& a) {
int n = sz(a) - 1;
vi next(n + 1, 0);
rep(i, 2, n + 1) {
int j = i - 1;
while(j && a[next[j] + 1] != a[i]) j = next[j];
if (j) next[i] = next[j] + 1;
}
return next;
}
int match(const vi& a, const vi& b) {
int n = sz(a) - 1, m = sz(b) - 1;
vi next = get_next(b);
int i = 1, j = 1;
int ret = 0;
while(i <= n) {
if (a[i] == b[j]) {
if (j == m) {
ret++;
j = next[j];
}
i++;
j++;
} else if (j == 1) {
i++;
} else {
j = next[j - 1] + 1;
}
}
return ret;
}
int main() {
int t; cin >> t;
while(t--) {
int n, m, k; cin >> n >> m >> k;
vi a(n + 1), b(m + 1);
rep(i, 1, n + 1) cin >> a[i];
rep(i, 1, m + 1) cin >> b[i];
vi da(n), db(m);
rep(i, 1, n) da[i] = ((a[i + 1] - a[i]) % k + k) % k;
rep(i, 1, m) {
db[i] = ((b[i] - b[i + 1]) % k + k) % k;
// db[i] = -db[i];
}
// rep(i, 1, n) dd(i), de(da[i]);
// rep(i, 1, m) dd(i), de(db[i]);
int ans = match(da, db);
cout << ans << '\n';
}
return 0;
}