題意:有個小盆友圍成一圈,從第個小朋友開始,選中誰誰退圈,每個小朋友都有一個數,這個數爲正數表明下一個選中的小朋友即爲這個小朋友左邊第個小朋友,爲負數表明下一個選中的小朋友爲這個小朋友右邊第個小朋友。每個小朋友退圈即可獲得的因子數的糖果數,爲這個小朋友是第幾個退圈的,輸出這個獲得最多的糖果的小朋友的名字和她獲得的糖果數。
思路:個小朋友,獲得最多的糖果的那個人的編號爲中有最多因子數的那個數,所以就需要求出反素數,以下是關於反素數的相關知識。
反素數的定義:對於任何正整數,其約數個數記爲,例如,如果某個正整數滿足:對任意的正整數 ,都有,那麼稱爲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;
}