(poi2012)有 n 次访问,每次来 Xi ( 1 <= i <= n ) 个,每个人取走一个 x 的倍数( 每个数只能被取走一次 ),并规定从当前可取的最小的倍数开始取;这些数中有 m 个被视作幸运数字,并告诉你分别是哪 m 个,求取走幸运数字的人的编号( 编号按顺序每次递增 1 ).
用一个数组 MX[ x ] 记录x的倍数中最小的能取的数是哪个,每次累加 x;这样复杂度就是 n(n / 1 + n / 2 + n / 3 + ... + n / n) = nlogn ( 调和级数 ).
/*
Author: JDD
PROG: bzoj2793.vouchers
DATE: 2015.11.03
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 1000005;
int m, n, M, mx[MAX_N];
bool L[MAX_N], vis[MAX_N];
long long ans[MAX_N];
void init()
{
scanf("%d", &m);
memset(L, 0, sizeof(L));
memset(vis, 0, sizeof(vis));
int x;
for(int i = 1; i <= m; i ++)
scanf("%d", &x), L[x] = 1,
M = max(x, M);
for(int i = 1; i <= 1000000; i ++) mx[i] = i;
}
void doit()
{
scanf("%d", &n);
long long cnt = 0;
while(n --){
int x; scanf("%d", &x);
int t = x;
for(int i = mx[x], k = 0; i <= M; i += x){
if(!vis[i]){
cnt ++; t --; k ++;
vis[i] = 1;
if(L[i]) ans[++ ans[0]] = cnt;
if(k == x) break;
}
mx[x] = i;
}
cnt += t;
}
printf("%lld\n", ans[0]);
for(int i = 1; i <= ans[0]; i ++) printf("%lld\n", ans[i]);
}
int main()
{
init(); doit();
return 0;
}
本文探讨了在特定访问次数和倍数取走规则下,幸运数字被取走的策略和算法实现,包括初始化、遍历和结果输出。
742

被折叠的 条评论
为什么被折叠?



