Codeforces Round #215 (Div. 2) D.Sereja ans Anagrams(巧用stl+利用之前数据的思想)

97 篇文章 0 订阅
20 篇文章 0 订阅

B. Sereja ans Anagrams

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 nm and p (1 ≤ n, m ≤ 2·105, 1 ≤ p ≤ 2·105). The next line contains n integers a1a2...an(1 ≤ ai ≤ 109). The next line contains m integers b1b2...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.

Examples
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


题意:

就是用两长度为n,m的数组,给定一个p,让你从第一个数组下标为1开始往后寻找满足起始位置p,数列Ap,Ap+1.。。Ap+(n-1)p,使得新数组中数字出现数目与第二个数组相同,打印出种类数目和起始位置

题解:

一开始因为看到是1e9的数据,用数组保存情况肯定爆炸,就陷入了沉思,后来ljw学长在群里发了题解,一开始看学长的博客没太看懂,百度了一下。。。后来感觉理解了那个博主的思路,然后就自己就写了一遍,这题的思路就是利用数据,工具就是stl,之前没用过map不知道map那么好用,就是我们在暴力从一个起点开始算的时候,当他的长度达到了m,我们可以去掉数组的第一个元素,加上数组的最后一个元素的后面的元素(在不超出n的范围内),并将遍历所有数组元素打上vis标记,下次遍历时标记了就直接跳掉,就省去了很多时间

代码:

#include<stdio.h>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int MAX=2e5+5;
int a[MAX];
int mul[MAX];
int vis[MAX];
map<int,int>M;//直接开数组,因为数据范围为1e9,会炸,所以只能用键值对
int main()
{
    int i,j,n,m,p,x;
    scanf("%d%d%d",&n,&m,&p);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=0;i<m;i++)
    {
        scanf("%d",&x);
            M[x]++;//记录数组情况
    }
    int ans=0,q;
    if((m-1)*p+1>n)//检查合法性
    {
        printf("0\n");
        return 0;
    }
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)//从数组第一个开始遍历
    {
        if(vis[i])//优化
            continue;
        queue<int>q;
        map<int,int>TM;//用于保存当前状态下的数组情况
        TM.clear();
        for(j=i;j<=n;j+=p)
        {
            q.push(j);
            vis[j]=1;//标记一下避免之后重复取耗时间
            TM[a[j]]++;
            if(q.size()>m)//判断是否达到了长度
            {
                x=q.front();
                q.pop();
                TM[a[x]]--;
                if(TM[a[x]]==0)//很重要,不擦掉会出事
                    TM.erase(a[x]);
            }
            if(TM==M)//巧用stl
            {
                mul[ans]=q.front();
                ans++;
            }
        }
    }
    sort(mul,mul+ans);//因为放入的时候不是按下标顺序,要从小到大排序
    printf("%d\n",ans);
    for(i=0;i<ans;i++)
    {
        printf("%d",mul[i]);
        if(i!=ans-1)
            printf(" ");
        else
            printf("\n");
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值