题意:有个小盆友围成一圈,从第
个小朋友开始,选中谁谁退圈,每个小朋友都有一个数
,这个数为正数表明下一个选中的小朋友即为这个小朋友左边第
个小朋友,为负数表明下一个选中的小朋友为这个小朋友右边第
个小朋友。每个小朋友退圈即可获得
的因子数的糖果数,
为这个小朋友是第几个退圈的,输出这个获得最多的糖果的小朋友的名字和她获得的糖果数。
思路:个小朋友,获得最多的糖果的那个人的编号为
中有最多因子数的那个数,所以就需要求出反素数,以下是关于反素数的相关知识。
反素数的定义:对于任何正整数,其约数个数记为,例如
,如果某个正整数满足:对任意的正整数
,都有
,那么称为n反素数。
从反素数的定义中可以看出两个性质:
(1)一个反素数的所有质因子必然是从开始的连续若干个质数,因为反素数是保证约数个数为的这个数尽量小
(2)同样的道理,如果,那么必有
对于这道题,我们直接按照反素数的定义枚举打表即可了:
#include <stdio.h>
#include <vector>
using namespace std;
const int maxn = 600005;
vector<int> antiprime,factor;
int get(int n)
{
int res,i,t;
res = 1;
for(i = 2; i * i <= n; i++) {
t = 0;
while(n % i == 0) {
t++;
n /= i;
}
res *= (t + 1);
}
if(n != 1)
res *= 2;
return res;
}
int main(void)
{
int i,Max,t;
Max = 0;
for(i = 1; i < maxn; i++) {
t = get(i);
if(t > Max) {
antiprime.push_back(i);
factor.push_back(t);
Max = t;
}
}
return 0;
}
这样我们就找出来了中有最多因子数的那个数
,然后我们找出来第
个出圈的小盆友就行了,如何求就用到了线段树,线段树存储的是区间还剩多少小朋友,知道现在要出圈的小朋友在此时此刻的圈里的位置
,根据他的数可以求出下一个要出圈的小朋友在此时此刻圈里的位置,注意在左边与在右边的求法不一样,在纸上画一画就知道了。然后就可以利用线段树求出这个小朋友在初始圈里的位置,知道这个位置就知道了他的数,这样循环求下去,就得到第
个出圈的小朋友。
#include <stdio.h>
#include <string.h>
#define lson num << 1
#define rson num << 1 | 1
#define maxn 500005
const int antiprime[] = {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,554400};
const int factor[] = {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,216};
struct node
{
int l,r,sum;
}tree[maxn << 2];
char name[maxn][20];
int val[maxn];
void pushup(int num)
{
tree[num].sum = tree[lson].sum + tree[rson].sum;
}
void build(int num,int l,int r)
{
tree[num].l = l;
tree[num].r = r;
if(l == r) {
tree[num].sum = 1;
return;
}
int mid = (l + r) >> 1;
build(lson,l,mid);
build(rson,mid + 1,r);
pushup(num);
}
int update(int k,int num,int l,int r)
{
if(l == r) {
tree[num].sum = 0;
return l;
}
int ans,mid;
mid = (l + r) >> 1;
if(k <= tree[lson].sum)
ans = update(k,lson,l,mid);
else
ans = update(k - tree[lson].sum,rson,mid + 1,r);
pushup(num);
return ans;
}
int main(void)
{
int i,n,k,cnt,pos;
while(scanf("%d %d",&n,&k) != EOF) {
for(i = 1; i <= n; i++)
scanf("%s %d",name[i],&val[i]);
cnt = 0;
while(antiprime[cnt] <= n)
cnt++;
cnt--;
build(1,1,n);
for(i = 0; i < antiprime[cnt]; i++) {
pos = update(k,1,1,n);
if(i == antiprime[cnt] - 1) break;
if(val[pos] > 0)
k = ((k - 1 + val[pos] - 1) % tree[1].sum + tree[1].sum) % tree[1].sum + 1;
else
k = ((k + val[pos] - 1) % tree[1].sum + tree[1].sum) % tree[1].sum + 1;
}
printf("%s %d\n",name[pos],factor[cnt]);
}
return 0;
}