Sereja ans Anagrams ------Codeforces Round # 215 div.1 B

http://codeforces.com/contest/367/problem/B


题意:

给你两个序列,你要从第一个序列中选出间隔为p的m个数,将这m个数重新排列之后,使之与第二个序列相同。

分析:

1.显然,最笨的办法就是枚举第一个数,每次都把m个数全部找出来,与b比较,用map来比较的话,这样做的时间复杂度为nmlogn左右,显然要T。

2.分组,只有i mod p相同的数才有可能被选在一起,于是分别把余数为0,1,2……提出来,对于每一串数,就相当于取连续的m个,使之成立。时间复杂度为q*n/q*logn=nlogn,于是就可以过了,更多处理细节看代码。


#include <cstdlib>
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
#define inf 2147480000
int n,m,p;
int aox[200001];
int box[200001];
map<int , int> k;
map<int , bool> q;
map<int , int > work;
int final[200001];
int final_o;
int o;
int main(int argc, char *argv[])
{
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++)
        scanf("%d",&aox[i]);
    for(int i=1;i<=m;i++)
        scanf("%d",&box[i]);
    sort(box+1,box+1+m);
    int now=-1;int num=0;
    for(int i=1;i<=m;i++)
    {
        if(now!=box[i])
        {
            now=box[i];
            q[box[i]]=1;
            o++;
            k[box[i]]=1;
        }
        else
        {
            k[box[i]]++;
        }
    }
    int pig=m*p;
    int cal=o;
    int mid;
    for(int i=1;i<=p;i++)
    {
        num=0;now=i;cal=o;
        work.clear();
        while(1)
        {
            if(now>n) break;
            if(num<m)
            {
                if(q[aox[now]])
                {
                    num++;
                    work[aox[now]]++;
                    if(work[aox[now]]==k[aox[now]])
                        cal--;
                    else if(work[aox[now]]==1+k[aox[now]])
                        cal++;
                    if(num==m)
                    {
                        if(cal==0)
                        {
                            final_o++;
                            final[final_o]=now-pig+p;
                        }
                    }
                }
                else
                {
                    work.clear();
                    cal=o;
                    num=0;
                }
            }
            else
            {
                if(q[aox[now]])
                {
                    mid=now-pig;
                    if(work[aox[mid]]==k[aox[mid]])
                        cal++;
                    work[aox[mid]]--;
                    if(work[aox[mid]]==k[aox[mid]])
                        cal--;
                    work[aox[now]]++;
                    if(work[aox[now]]==k[aox[now]])
                        cal--;
                    else if(work[aox[now]]==k[aox[now]]+1)
                        cal++;
                    if(cal==0)
                    {
                        final_o++;
                        final[final_o]=now-pig+p;
                    }
                }
                else
                {
                    work.clear();
                    cal=o;
                    num=0;
                }
            }
            now=now+p;
        }
    }
    sort(final+1,final+1+final_o);
    cout<<final_o<<endl;
    for(int i=1;i<=final_o;i++)
    {
        cout<<final[i]<<" ";
    }
    cout<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值