Who Gets the Most Candies?
POJ - 2886
反素数 + 线段树
题意:有n个人围成一圈,游戏的起点是k,每个人持有一个数字(非编号)num,每次当前的人退出圈,下一个人是他左边的第num个(也就是说下一个退出的是k+num, k可以为负数,表示右边的第num个), 现在一直如果一个人是第i个推出的,那么他的得分就是i的因数的个数,球得分最高的那个人的编号
题解:先求出小于等于n的里面所有的数字里面应该获得最高分的那个出圈id,按照区间人数建立线段树,依次出圈
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<stack>
#include<cstdlib>
#include<queue>
#include<set>
#include<string.h>
#include<vector>
#include<deque>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define eps 1e-4
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl;
#define Mod(a,b) a<b?a:a%b+b
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;
}