poj 2886

       题意: N个小孩围成一圈,他们被顺时针编号为 1 到 N。每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的,则是右手边的第 A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。

   分析:用线段树的单点更新实现某个小孩离开圈的操作,并得到下一个要离开的小孩的编号,至于如何知道谁得到的糖最多,打个反素数表就行了。

代码如下:

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <list>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lrt rt << 1
#define rrt rt << 1|1
#define root 1,n,1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const LL INF = (((LL)1)<<62)+1;
using namespace std;
const double eps = 1e-5;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const double M=1e-8;
const int N=500100;
typedef pair<int, int> pii;
typedef pair<int, string> pis;
const int d[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int n,k,m,st[N*4],lazy[N*4];
int p[]={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,665280
                      };
int pNum[]={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,224
                      };
LL ans,moresum;
int id[N];
struct node
{
    char name[20];
    int val;
};
node a[N];
void build(int l,int r,int rt)
{
    st[rt]=r-l+1;
    if (l==r) return ;
    int mid=MID(l,r);
    build(lson);
    build(rson);
}
int updata(int k,int l,int r,int rt)
{
    if (l==r) {
        st[rt]--;
        return r;
    }
    int mid=MID(l,r),t;
    if (k<=st[rt<<1]) t=updata(k,lson);
    else t=updata(k-st[rt<<1],rson);
    st[rt]=st[lrt]+st[rrt];
    return t;
}
int main()
{
    int i,j,&mod=st[1];
    while(~scanf("%d%d",&n,&k))
    {
        int pos=0;
        while(p[pos]<=n) pos++;
        for (i=1;i<=n;i++) {
            scanf("%s %d",a[i].name,&a[i].val);
            //cin>>name[i] >>id[i];
        }
        int v=0,u;   // 从0开始编号
        build(root);
        a[v].val=0;
        for(i=0;i<p[pos-1];i++)
        {
            if(a[v].val>0)
                k=((k+a[v].val-2)%mod+mod)%mod+1;  
            else
                k=((k+a[v].val-1)%mod+mod)%mod+1;
            v=updata(k,1,n,1);                 // 让第k个人出列,并且得到他原始序列中的编号v
        }
        //for (i=1;i<2*r;i++) cout<<st[i]<<" "; cout<<endl;
        printf("%s %d\n",a[v].name,pNum[pos-1]);
    }
}





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值