poj2886线段树+反素数

来源:互联网 发布:淘宝睡衣模特是谁 编辑:程序博客网 时间:2024/05/16 19:08

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 500040char 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;}