8<---------------------------------------------------
题意:
N个小朋友围一圈。
指定一个人为起始点之后,此人出圈。
按照这个人手中卡片的数字找到下一个人,下一个人出圈。
。。。
直到最后一个人出圈。
8<--------------------------------------------
思路:
一:当期指定的人在第 K 个位置,他出圈后,找到下一个人在剩下的人中的位置 next_k。
if(A >= 0) next_k = (k-1+A-1)%n + 1;
else next_k = ((k-1+A)%n + n)%n + 1;
二:利用线段树树状数组求出接下来出圈的人原来的所在的位置。
以此可以求得第 P 个除圈的人。
三:题目描述最后一句说 F( x )为 x 的约数的个数。求这一组数的最大的 F(x),输出x, 以及相应的人名。
此处需要反素数表。
利用反素数相关知识,求出小于 N 的最大反素数 F(X), 得到X。
利用思路二可以求出第F(X)个出圈的人。
输出人名和x。
8<-------------------------------------------
刚开始不知道用到反素数,只暴力球了各个数的因子个数,无数个WA 和 超时, 错误百出。
搜了一下题解,用的反素数打表。
第一次接触反素数,了解了一下发现维基 和 百度说法不一。
不过总算知道是什么了。
啊, 第一次纯手写线段树不用看模板,脑海中的线段树模板有区间查询,这里是根据一个特定的值查询,稍微改了一下就好使了。
(呃。。。。我费了好长时间写这个查询啊……甚至还写了二级查询……慢慢调才搞出来简短的这个……当然代码里看不出来啦……弱弱仍需努力……)
8<---------------------------------------------
/*poj2886线段树*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define maxn 500040
char str[maxn][10];
int A[maxn];
int sum[maxn<<2];
int n, k;
int operate(int a, int b){
return a+b;
}
void PushUp(int rt){
sum[rt] = operate(sum[rt<<1], sum[rt<<1|1]);
}
void build(int l, int r, int rt){
if(l == r){
sum[rt] = 1;
return ;
}
int m = (l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void Update(int p, int add, int l, int r, int rt){
if(l == r){
sum[rt] = add;
return ;
}
int m = (l+r)>>1;
if(p <= m) Update(p, add, lson);
else if(p>m) Update(p, add, rson);
PushUp(rt);
}
int Query(int k, int l, int r, int rt){
if(l==r && k == 1 && sum[rt] == k){
return l;
}
int m = (l+r)>>1;
int ret = 0;
if(sum[rt<<1] < k){
ret = Query(k-sum[rt<<1], rson);
}else if(sum[rt<<1] >= k){
ret = Query(k, lson);
}
return ret;
}
int main(){
//freopen("in.txt", "r", stdin);
int maxp_pos, maxp;
int a[37]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,
5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,
166320,221760,277200,332640,498960,500001};
int b[37]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,
90,96,100,108,120,128,144,160,168,180,192,200,1314521};
while(scanf("%d %d", &n, &k) != EOF){
memset(sum, 0, sizeof(sum));
for(int i=1; i<=n; i++){
scanf("%s %d", str[i], &A[i]);
}
build(1, n, 1);
int i=0;
while(a[i] <= n) i++;
int p = a[i-1];
maxp = b[i-1];
int cnt = 1, next_k = k, tmp = k;
int tmp_n = n;
while(cnt<n){
cnt++;
Update(tmp, 0, 1, n, 1);
tmp_n --;
if(A[tmp]>=0) next_k = (next_k-1+A[tmp]-1)%tmp_n+1;
else next_k = ((next_k-1+A[tmp])%tmp_n+tmp_n)%tmp_n + 1;
tmp = Query(next_k, 1, n, 1);
if(cnt == p) maxp_pos = tmp;
}
printf("%s %d\n", str[maxp_pos], maxp);
}
return 0;
}