BZOJ-2793: [Poi2012]Vouchers

[文章目录]

Description

考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个。正整数中有m个数被标成了幸运数,问有哪些人取到了幸运数。n<=1000000,m<=1000000,x<=1000000

每个数的倍数个数和是nlnn的(调和级数)。
那么每次来x人,我们从上次来x人时扫到的位置继续扫,找下x个没有被标记的。总时间复杂度nlnn(POI的题好像都有些脑洞呢)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int lim=1000000;
ll ans[1001000];
int n,m;
inline char nc()
{
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
    x=0; char ch=nc();
    while(ch<'0'||ch>'9') ch=nc();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=nc();
}
bool luck[1001000],vis[1001000];
int nxt[1001000];
int main()
{
    read(m); int x;
    while(m--)
    {
        read(x);
        luck[x]=1;
    }
    read(n); ll id=0; int i,now,top=0;
    while(n--)
    {
        read(x); now=nxt[x]+x;
        for(i=1;i<=x;++i)
        {
            while(now<=lim&&vis[now]) now+=x;
            if(now>lim) break;
            vis[now]=1; if(luck[now]) ans[++top]=id+i;
        }
        nxt[x]=now; id+=x;
    }
    printf("%d\n",top);
    for(int i=1;i<=top;++i) printf("%lld\n",ans[i]);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注