匹配

题目描述

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("");
    }
}

 

posted @ 2018-08-05 22:32  iamunstoppable  阅读(593)  评论(0编辑  收藏  举报