Who Gets the Most Candies?(约瑟夫环+反素数+插队)
发布日期:2021-07-14 01:03:45 浏览次数:56 分类:技术文章

本文共 4357 字,大约阅读时间需要 14 分钟。

传送门

描述

N children are sitting in a circle to play a game.

The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the integer on his card and jumps out of the circle. The integer on his card tells the next child to jump out. Let A denote the integer. If A is positive, the next child will be the A-th child to the left. If A is negative, the next child will be the (−A)-th child to the right.
The game lasts until all children have jumped out of the circle. During the game, the p-th child jumping out will get F(p) candies where F(p) is the number of positive integers that perfectly divide p. Who gets the most candies?

输入

There are several test cases in the input. Each test case starts with two integers N (0 < N ≤ 500,000) and K (1 ≤ K ≤ N) on the first line. The next N lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 108) on their cards in increasing order of the children’s numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.

输出

Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.

样例

  • Input
    4 2
    Tom 2
    Jack 4
    Mary -1
    Sam 1
  • Output
    Sam 3

思路

  • 题意:约瑟夫出列问题,给出人数n和初始出列位置k,然后给出每个人的id和val,val>0则从k右边数val个,val<0则从k左边数val个。样例出队顺序:jack->Mary->Tom->Sam,我们给他们顺序标号tem,那么每个人出队的时候都可以得到p(tem)个糖果,p(tem)表示tem的因子个数,如p(4)=3(1,2,4);求得到糖果最多的人和糖果数0则从k左边数val个。样例出队顺序:jack->
  • 我们通过k和当前的val[i]可以确定下一个要出队的人是 剩下的 队伍中的第几个:若val>0,从k-1(因为自己被移除了)往后面数val个然后%剩余人数,即:k=(k-1+val[i])%(n-i)为了防止1%1=0的情况,写成这种方式:k=(k-1+val[i]-1)%(n-i)+1;若val<0,则从k往前数val个再加上剩余人数,然后%剩余人数,同样要防止1%1=0的情况,即`k=((k+mes[tem].val-1)%(n-i)+n-i)%(n-i)+1;`。 样例的k值为2-="">2->1->1。0,则从k往前数val个再加上剩余人数,然后%剩余人数,同样要防止1%1=0的情况,即`k=((k+mes[tem].val-1)%(n-i)+n-i)%(n-i)+1;`。>
  • 确定了下一个出队的人在第几个剩余人中的第几个之后,就要通过线段树插队找到他原来的位置,如果他现在是第k个,而前面k已经有人了,那么就往后摞,直到有位置可以放,这个位置就是它原来的位置。
  • 反素数:对于数n,任何小于n的数的因子数都小于n的因子数,那么n就是一个反素数。
    1 2 3 4 5 6 7 8 9 10
    int ip[] = {
    0,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 div1[] = {
    0,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 };//反素数对应的约数个数

我们要找到小于n且最接近n的反素数,答案就是它的因子个数。

也可以直接打表求每个数的因子个数

Code

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#include
#include
#include
#include
#include
#include
#include
using namespace std; #define CRL(a) mamset(a,0,sizeof(a)) typedef long long ll; const int N=5e5+5; int tree[N*4]; int ans[N]; int ip[] = { 0,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 div1[] = { 0,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 };//反素数对应的约数个数 struct node{ char s[20];//string直接t掉 int val; }mes[N]; void build(int l,int r,int d){ tree[d]=r-l+1; if(l==r)return; int mid=(l+r)/2; build(l,mid,d<<1); build(mid+1,r,d<<1|1); } int update(int l,int r,int num,int d){ tree[d]--; if(l==r)return l; int mid=(l+r)/2; if(num<=tree[d<<1]) return update(l,mid,num,d<<1); else return update(mid+1,r,num-tree[d<<1],d<<1|1); } int main() { ios::sync_with_stdio(false); int n,k,tem,res; while(cin>>n>>k){ res=0; for(int i=1;ip[i]<=n;i++) res=i; build(1,n,1); for(int i=1;i<=n;i++) cin>>mes[i].s>>mes[i].val; for(int i=1;i<=n;i++){ tem=update(1,n,k,1); if(i==ip[res]){ cout<
<<" "<
<
0) k=(k-1+mes[tem].val-1)%(n-i)+1; else k=((k+mes[tem].val-1)%(n-i)+n-i)%(n-i)+1; } } return 0; }

转载地址:https://blog.csdn.net/cpongo3/article/details/89334298 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:无题II(二分+匈牙利)
下一篇:Going Home (最小权值完备匹配)

发表评论

最新留言

很好
[***.229.124.182]2024年03月31日 22时23分37秒