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; }