Poj--2886(线段树 or 树状数组,二分,反素数)

2014-10-01 15:31:32

思路:这题调了我N久,二分的基础还是弱QAQ。我的方法是:用首先用树状数组来维护出入队的情况,初始1-N都是1,第k个人出队,则k的位置减一。在找下一个人的位置的时候用二分,注意:二分查到的位置不能是已经出队的人!借鉴了别人优雅的反素数求法。~~~~

 1 /*************************************************************************
 2     > File Name: 2886.cpp
 3     > Author: Nature
 4     > Mail: 564374850@qq.com
 5     > Created Time: Tue 30 Sep 2014 09:32:25 PM CST
 6 ************************************************************************/
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <cstdlib>
11 #include <cmath>
12 #include <vector>
13 #include <queue>
14 #include <iostream>
15 #include <algorithm>
16 using namespace std;
17 #define lpos (pos << 1)
18 #define rpos (pos << 1|1)
19 #define getmid(l,r) (l + (r - l) / 2)
20 typedef long long ll;
21 const int INF = 1 << 30;
22 const int maxn = 500010;
23 
24 int ans,ansn,N,K;
25 char name[maxn][15];
26 int c[maxn],card[maxn];
27 int fnum[maxn],atp[maxn];
28 
29 int Lowbit(int x){ return x & (-x);}
30 void Update(int x,int d){while(x <= N){ c[x] += d,x += Lowbit(x);}}
31 int Getsum(int x){int res = 0;while(x){ res += c[x],x -= Lowbit(x);} return res;}
32 
33 void Pre(){
34     memset(fnum,0,sizeof(fnum));
35     for(int i = 1; i <= maxn; ++i)
36         for(int j = i; j <= maxn; j += i)
37             ++fnum[j];
38     ansn = 0;
39     for(int i = 1; i <= N; ++i){
40         if(fnum[i] > ansn){
41             ans = i;
42             ansn = fnum[i];
43         }
44     }
45 }
46 
47 int B_search(int k){
48     int l = 1,r = N,mid,tmp;
49     while(l < r){
50         mid = getmid(l,r);
51         tmp = Getsum(mid);
52         if(tmp < k)    l = mid + 1;
53         else    r = mid;
54     }
55     return l;
56 }
57 
58 int main(){
59     scanf("%d%d",&N,&K);
60     Pre();
61     for(int i = 1; i <= N; ++i){
62         scanf("%s%d",name[i],&card[i]);
63         Update(i,1);
64     }
65     int pos = K,sum = N,next,ln,rn,cnt = 0;
66     while(cnt < ans - 1){
67         Update(pos,-1);
68         --sum;
69         ln = Getsum(pos);
70         rn = sum - ln;
71         if(card[pos] > 0){
72             card[pos] %= sum;
73             if(card[pos] == 0) card[pos] = sum;
74             if(card[pos] <= rn)
75                 next = B_search(ln + card[pos]);
76             else
77                 next = B_search(card[pos] - rn);
78         }
79         else{
80             card[pos] = -card[pos];
81             card[pos] %= sum;
82             if(card[pos] == 0) card[pos] = sum;
83             if(card[pos] <= ln)
84                 next = B_search(ln - card[pos] + 1);
85             else
86                 next = B_search(sum - (card[pos] - ln) + 1);
87         }
88         pos = next;
89         cnt++;
90     }
91     printf("%s %d\n",name[pos],ansn);
92     return 0;
93 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4003310.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值