LightOJ 1097 - Lucky Number [线段树二分前缀和构造数列]

1097 - Lucky Number
Time Limit: 2 second(s)Memory Limit: 64 MB

Lucky numbers are defined by a variation of the well-known sieve of Eratosthenes. Beginning with the natural numbers strike out all even ones, leaving the odd numbers 1, 3, 5, 7, 9, 11, 13, ... The second number is 3, next strike out every third number, leaving 1, 3, 7, 9, 13, ... The third number is 7, next strike out every seventh number and continue this process infinite number of times. The numbers surviving are called lucky numbers. The first few lucky numbers are:

1, 3, 7, 9, 13, 15, 21, 25, 31, 33, ...

In this problem your task is to find the nth lucky number where n is given in input.

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer n (1 ≤ n ≤ 105).

Output

For each case, print the case number and the nth lucky number.

Sample Input

Output for Sample Input

2

2

100000

Case 1: 3

Case 2: 1429431

 


PROBLEM SETTER: MOHAMMED SHAMSUL ALAM
SPECIAL THANKS: JANE ALAM JAN (DESCRIPTION, SOLUTION, DATASET)

这道题过的让我觉得有点突然。。。。
题目大意是,先给你一个奇数组成的数列a,依次划去数列中下标为a[i]的倍数的数。
题目友善的地方是。。样例给了边界~这就很爽很爽了~


直接用线段树构造数列。。不过我不知道在我的电脑上跑了好久怎么交上去才跑200ms。。。。
代码:

#include <bits/stdc++.h>
using namespace std;

const int MAX_N = 1429431+100;
int sum[MAX_N<<2],T;

void build(int idx,int l,int r){
    if( l==r ){
        if(l&1) sum[idx] = 1;
        else sum[idx] = 0;
        return;
    }
    int m = (l+r)>>1;
    build(idx<<1,l,m);
    build(idx<<1|1,m+1,r);
    sum[idx] = sum[idx<<1]+sum[idx<<1|1];
}

int query(int x,int idx,int l,int r){
    if( l==r ) return l;
    int m = (l+r)>>1;
    if(sum[idx<<1]>=x) return query(x,idx<<1,l,m);
    else return query(x-sum[idx<<1],idx<<1|1,m+1,r);
}

int update(int pos,int x,int idx,int l,int r){
    if( l==r ) {
        sum[idx] = x;
        return l;
    }
    int m = (l+r)>>1;
    int res = 0;
    if( sum[idx<<1]>=pos ) res = update(pos,x,idx<<1,l,m);
    else res = update(pos-sum[idx<<1],x,idx<<1|1,m+1,r);
    sum[idx] = sum[idx<<1] + sum[idx<<1|1];
    return res;
}

int main(){
    build(1,1,MAX_N);
    int now = 2;
    while( sum[1]>=now ){
        int t = query(now,1,1,MAX_N);
        int nowt = t;
        bool flag = false;
        while(sum[1]>=nowt){
            flag = true;
            int res = update(nowt,0,1,1,MAX_N);
            nowt+=t-1;
        }
        if(!flag) break;
        now++;
    }
    //printf("%d\n",sum[1]);
    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        int num;
        scanf("%d",&num);
        int ans = query(num,1,1,MAX_N);
        printf("Case %d: %d\n",t,ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值