bzoj 2793: [Poi2012]Vouchers 乱搞

来源:互联网 发布:la域名收录怎么样 编辑:程序博客网 时间:2024/06/05 09:19

题意

考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个。
正整数中有m个数被标成了幸运数,问有哪些人取到了幸运数。
第一行一个正整数m (m<=1,000,000),下面m行每行一个正整数x (x<=1,000,000),表示x是一个幸运数。
接下来一行一个正整数n (n<=1,000,000),下面n行每行一个正整数x (x<=1,000,000),表示这一组来了x个人。
第一行输出一个非负整数k,表示k个人取到了幸运数,下面k行依次表示取到幸运数的人的编号,人按照来的顺序从1开始编号。

分析

因为取到大于最大的幸运数的数是对答案没有影响的,所以实际能取的数不超过1e6。那么我们可以开一个桶a[x]表示取x的倍数的人从头开始取取到了哪个数,然后每次一直往后跳即可。
复杂度O(nlogn)

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=1000005;int a[N],tot;LL ans[N];bool vis[N],tag[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    int m=read(),mx=0;    for (int i=1;i<=m;i++)    {        int x=read();        tag[x]=1;mx=max(mx,x);    }    int n=read();LL now=0;vis[0]=1;    while (n--)    {        int x=read();        for (int i=1;i<=x;i++)        {            while (vis[a[x]]&&a[x]+x<=mx) a[x]+=x;            if (!vis[a[x]])            {                vis[a[x]]=1;                if (tag[a[x]]) ans[++tot]=now+i;            }            else break;        }        now+=x;    }    printf("%d\n",tot);    for (int i=1;i<=tot;i++) printf("%lld\n",ans[i]);    return 0;}