Codeforces Round #215 (Div. 2) D题(离散化+hash)

D. Sereja ans Anagrams
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Sereja has two sequences a and b and number p. Sequence a consists of n integers a1, a2, ..., an. Similarly, sequence b consists of mintegers b1, b2, ..., bm. As usual, Sereja studies the sequences he has. Today he wants to find the number of positions q (q + (m - 1)·p ≤ nq ≥ 1), such that sequence b can be obtained from sequence aq, aq + p, aq + 2p, ..., aq + (m - 1)p by rearranging elements.

Sereja needs to rush to the gym, so he asked to find all the described positions of q.

Input

The first line contains three integers n, m and p (1 ≤ n, m ≤ 2·105, 1 ≤ p ≤ 2·105). The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109). The next line contains m integers b1, b2, ..., bm (1 ≤ bi ≤ 109).

Output

In the first line print the number of valid qs. In the second line, print the valid values in the increasing order.

Sample test(s)
input
5 3 1 1 2 3 2 1 1 2 3
output
2 1 3
input
6 3 2 1 3 2 2 3 1 1 2 3
output
2 1 2

题意:很容易理解。

分析:离散化->用hash进行线性求解

比赛的时候没有做出来,后来看了别人的思路,然后自己敲了遍代码,贡献了一次超时和两次Runtime Error,不过从中也得到一些收获,题目中a数组和b数组的元素范围为1<=ai,bi<=10^9,此范围比较大,开数组进行hash不好弄,所以第一步就是离散化,离散化之后就是hash进行求解,实践复杂度为线性的,具体看代码实现。

代码实现:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n,m,p,total,flag,now;
int a[400005],b[400005],c[400005],all[400005],visited[400005];

void hebing()//合并成一个数组,全部存在c数组里
{
    int i,j,x;
    total=0;
    for(i=1;i<=n;i++)
     c[++total]=a[i];
    for(i=1;i<=m;i++)
     c[++total]=b[i];
    sort(c+1,c+1+total);
    x=0;
    for(i=1;i<=total;i++)//去重
     if(i==1||c[i]!=c[i-1])
      c[++x]=c[i];
    total=x;
}

int find(int x)//二分查找x处在c数组中的位置
{
    int l=1,r=total+1,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(c[mid]==x)
         return mid;
        else if(c[mid]>x)
         r=mid-1;
        else
         l=mid+1;
    }
}

void lisanhua()//对a数组和b数组进行离散化
{
    int i;
    for(i=1;i<=n;i++)
     a[i]=find(a[i]);
    for(i=1;i<=m;i++)
     b[i]=find(b[i]);
}

void init()
{
    int i;
    flag=0;
    memset(all,0,sizeof(all));
    for(i=1;i<=m;i++)//哈希处理b数组的情况
    {
        if(all[b[i]]==0)
         flag++;
        all[b[i]]++;
    }
}

void add(int x)
{
    visited[x]++;
    if(visited[x]==all[x])
     now++;
}

void del(int x)
{
    visited[x]--;
    if(visited[x]+1==all[x])
     now--;
}

void solve()
{
    int res[200005],num=0,i,j,k;
    for(i=1;i<=p;i++)//因为相隔为p,所以只需枚举1-p,然后对每一种序列滚动过去
    {
        if((i+(long long)(m-1)*p)<=n)//因为(m-1)*p已经超过int型,所以要强制转换成long long
        {                            //否则就会出现Runtime Error
            now=0;
            for(j=0;j<m;j++)
             add(a[i+j*p]);
            if(now==flag)
             res[num++]=i;
            for(j=i+p;(j+(long long)(m-1)*p)<=n;j=j+p)//滚动过去
            {
                del(a[j-p]);
                add(a[j+(m-1)*p]);
                if(now==flag)
                 res[num++]=j;
            }
            for(k=0;k<m;k++)//把加了的删掉,开始我用了memset(visited,0,sizeof(visited));
             del(a[j-p+k*p]);//然后果断超时了
        }
    }
    printf("%d\n",num);
    sort(res,res+num);
    for(i=0;i<num;i++)
     if(i!=num-1)
      printf("%d ",res[i]);
     else
      printf("%d\n",res[i]);
}

int main()
{
    int i,j;
    scanf("%d%d%d",&n,&m,&p);
    {
        for(i=1;i<=n;i++)
         scanf("%d",&a[i]);
        for(i=1;i<=m;i++)
         scanf("%d",&b[i]);
        hebing();
        lisanhua();
        init();
        solve();
    }
    return 0;
}

 

posted on 2013-11-27 21:27  后端bug开发工程师  阅读(833)  评论(2编辑  收藏  举报

导航