线段树题集

Who Gets the Most Candies?

 POJ - 2886 

反素数 + 线段树

题意:有n个人围成一圈,游戏的起点是k,每个人持有一个数字(非编号)num,每次当前的人退出圈,下一个人是他左边的第num个(也就是说下一个退出的是k+num, k可以为负数,表示右边的第num个), 现在一直如果一个人是第i个推出的,那么他的得分就是i的因数的个数,球得分最高的那个人的编号

题解:先求出小于等于n的里面所有的数字里面应该获得最高分的那个出圈id,按照区间人数建立线段树,依次出圈

#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include<string.h>
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define eps 1e-4
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<#define Mod(a,b) a
typedef long long LL;
typedef long long ll;
const int maxn = 5e5 + 5;

int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

int ans,n;
int best;

void dfs(int dept,int tmp,int num) {
    //到叶子结点,返回
    if (dept >= 16) return;
    //num记录的因子个数,如果遇到更小的,就更新
    if (num > best) {
        best = num;
        ans = tmp;
    }
    //当因子个数相同时,取值最小的
    if (num == best && ans > tmp) ans = tmp;
    for (int i = 1; i <= 63; i++) {
        if (n / p[dept] < tmp) break;
        dfs(dept + 1, tmp *= p[dept], num * (i + 1));
    }
}

int a[maxn],num[maxn],st[maxn << 2];
char name[maxn][20];
void build(int o, int l, int r) {
    if(l == r) st[o] = a[l];
    else {
        int mid = (l + r) >> 1;
        build(o << 1, l, mid);
        build(o << 1 | 1, mid + 1, r);
        st[o] = st[o << 1] + st[o << 1 | 1];
    }
}



int query(int pos,int o,int l,int r) {
    st[o]--;
    if(l == r) return l;
    int mid = (l + r) >> 1;
    int ans;
    if (st[o << 1] >= pos) ans = query(pos,o << 1, l, mid);
    else {
        pos -= st[o << 1];
        ans = query(pos, o << 1 | 1, mid + 1, r);
    }
    return ans;
}
int solve(int x) {
    int tmp = (int)sqrt(x * 1.0),ans = 0;
    for(int i = 1; i <= tmp; i++) {
        if (x % i == 0 && i != x / i) {
            ans += 2;
        } else if(x % i == 0)
            ans += 1;
    }
    return ans;
}
int main() {
    int k;
    while (~scanf("%d %d", &n, &k)) {
        ans = INF;
        best = 0;
        dfs(0, 1, 1);
        for (int i = 1; i <= n; i++) {
            scanf("%s %d",name[i], &num[i]);
            a[i] = 1;
        }
        build(1, 1, n);
        int ret;
        for (int i = 1; i <= ans; i++) {
            int pos = k;
            ret = query(pos, 1, 1, n);
            pos = num[ret];

            if(st[1] == 0) break;
            if(pos > 0) pos = ((k - 2 + st[1]) % st[1] + pos) % st[1] + 1;
            else pos = ((k + pos - 1) % st[1] + st[1]) % st[1] + 1;
            k = pos;
        }
        printf("%s %d\n",name[ret],solve(ans));

    }
    return 0;
}
View Code

 

你可能感兴趣的:(线段树题集)