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;
}