匹配
题目描述
Chino和Kokoa想好了装饰方案,装饰方案为一个长为m的数列。此外,她们还有一个模板方案,为一个长为n的数列。两个数列A,B匹配的定义为:匹配的定义改为:存在一个字符的映射,使得A应用这个映射之后等于B,且这个映射必须为一个排列。
A=121,B=313,当映射为{1→3,2→1,3→2}时A′=B,可以匹配。
A=212,B=313,当映射为{1→1,2→3,3→2}时A′=B,可以匹配。
A=232,B=313,当映射为{1→2,2→3,3→1}时A′=B,可以匹配。
A=123,B=111,当映射为{1→1,2→1,3→1}时A′=B,但此时映射不为一个排列,不能匹配。
Chino想知道模板序列有哪些连续子序列和她们想的序列匹配。
输入
第一行两个数t和c t为数据组数,c为字符集大小
每组数据:
第一行两个数n,m
第二行n个数表示模板序列
第三行m个数表示装饰序列
输出
每组数据第一行一个数表示该组数据答案个数
第二行若干个数表示合法序列的开头位置(升序)
样例输入
3 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3
样例输出
3
1 2 4
4
1 2 3 4
3
2 3 4
提示
数据范围:
10% n,m,c<=1e3
另外20% n,m<=1e5 c<=40
另外30% n,m,c,<=1e5
100% n,m,c<=1e6,t<=3
考虑对一个序列进行hash,每个位置i的值可以定义为i-这个元素上一次出现的位置。
如果是首次出现,那么就是0。这个东西显然可以递推。
#include <bits/stdc++.h> using namespace std; #define M 1000010 #define MOD 1000000007 int n, m, C; int head[M], Ne[M], fr[M]; int P[M]; int a[M], b[M]; vector<int> V; inline void solve(int H) { V.clear(); memset(head, 0, sizeof(head)); memset(fr, 0, sizeof(fr)); memset(Ne, 0, sizeof(Ne)); for(int i = n; i >= 1; -- i) { fr[head[a[i]]] = i; Ne[i] = head[a[i]]; head[a[i]] = i; } int wt = 0; for(int i = 1; i <= m; ++ i) { if(fr[i] == 0) { wt = (1ll * wt * 1000003) % MOD; } else wt = (1ll * wt * 1000003 + (i - fr[i])) % MOD; } if(wt == H) V.push_back(1); for(int i = 2; i <= n - m + 1; ++ i) { wt = 1ll * wt * 1000003 % MOD; int N = i + m - 1; if(Ne[i - 1] < N && Ne[i - 1]) wt -= (1ll * (Ne[i - 1] - (i - 1)) * P[N - Ne[i - 1]] % MOD); if(wt < 0) wt += MOD; if(fr[N] >= i) { wt += N - fr[N]; if(wt >= MOD) wt -= MOD; } if(wt == H) V.push_back(i); } } int main() { int T; scanf("%d%d", &T, &C); P[0] = 1; for(int i = 1; i <= 1000000; ++ i) { P[i] = 1ll * P[i - 1] * 1000003 % MOD; } while(T --) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]); for(int i = 1; i <= m; ++ i) scanf("%d", &b[i]); memset(head, 0, sizeof(head)); memset(fr, 0, sizeof(fr)); for(int i = m; i >= 1; -- i) { fr[head[b[i]]] = i; head[b[i]] = i; } int H = 0; for(int i = 1; i <= m; ++ i) { if(fr[i] == 0) { H = (1ll * H * 1000003) % MOD; } else H = (1ll * H * 1000003 + (i - fr[i])) % MOD; } solve(H); printf("%d\n", V.size()); for(int i = 0; i < V.size(); ++ i) { printf("%d ", V[i]); } puts(""); } }