BZOJ2793/POI2012 Vouchers

Task

考慮正整數集合,現在有n組人依次來取數,假設第i組來了x人,他們每個取的數一定是x的倍數,並且是還剩下的最小的x個。
正整數中有m個數被標成了幸運數,問有哪些人取到了幸運數。

m<=1,000,000, n<=1,000,000, x<=1,000,000.

Solution

對於每個來的人數x(無論人數爲x有幾組),最多要計算mxx 次,mx 爲最大的幸運數,那麼對於所有x ,計算的總次數就是:

mx+mx2+mx3+mx4+mxmaxx (maxx 表示人數的最大值)

=mx(1+12+13+14+....+1maxx)
通過調和級數,可以確定暴力是足夠的.因此直接記錄每個x,當前的最小的倍數f[x]即可.再暴力更新,查找幸運數.

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
#include<queue>
using namespace std;
inline void rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<1)+(res<<3)+(c^48);
    while(c=getchar(),c>=48);
}
inline void print(ll x){
    if(!x)return ;
    print(x/10);
    putchar((x%10)^48);
}
inline void sc(ll x){
    if(x<0){x=-x;putchar('-');}
    print(x);
    if(!x)putchar('0');
    putchar('\n');
}
const int M=1000005;
int n,mark[M],rec[M];
ll A[M];
int main(){
    int i,j,k,a,b,mx=0,m=0;
    ll tot=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        rd(a);
        mark[a]=1;
        mx=max(mx,a);
    }
    rd(n);
    for(i=1;i<=n;i++){
        rd(a);
        int st=a,c=0;
        if(rec[a]){
            if(rec[a]<=mx)st=rec[a]+a;
            else st=mx+1;
        }
        for(j=st;j<=mx;j+=a){
            if(mark[j]==-1)continue;
            else {
                c++;
                if(mark[j]==1)A[m++]=tot+c;
                mark[j]=-1;
                if(c==a)break;
            }
        }
        rec[a]=j;
        tot+=a;
    }
    printf("%d\n",m);
    for(i=0;i<m;i++)sc(A[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章