POJ - 2886 Who Gets the Most Candies

筛法+划分树。

枚举因子,类似筛法计算因子数量,复杂度为n/2 + n/3 + ... + n/n ≈ O(nlogn)。

值域已知,只有删除操作,寻找kth,用划分树就好了O(nlogn)。二分+树状数组也可以,只是复杂度多乘一个logn。

/*********************************************************
*            ------------------                          *
*   author AbyssalFish                                   *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
using namespace std;

const int MAX_SIZE = 1<<20, MAX_N = 5e5, LEN = 11;

int s[MAX_SIZE];
int N, K;
#define para int o = 1, int l = 0,int r = N-1
#define Tvar int mid = (l+r)>>1, lc = (o<<1), rc = (o<<1|1);
#define lsn lc, l, mid
#define rsn rc, mid+1, r

void build(para)
{
    s[o] = r-l+1;
    if(l == r) return;
    else {
        Tvar
        build(lsn);
        build(rsn);
    }
}

int q_modify(int k, para)
{
    s[o]--;
    if(l == r){
        return l;
    }
    else {
        Tvar
        if(k<=s[lc]) return q_modify(k, lsn);
        return q_modify(k-s[lc], rsn);
    }
}

char name[MAX_N][LEN];
int card[MAX_N];

int Fp[MAX_N+1];



#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    //cout<<(1<<20);//ceil(log2(5e5)+1);
    scanf("%d%d",&N,&K);
    for(int i = 2; i <= N; i++){
        for(int j = i; j <= N; j += i){
            Fp[j]++;
        }
    }
    int tar = 1;
    for(int i = 2; i <= N; i++){
        if(Fp[tar] < Fp[i]) tar = i;
    }
    for(int i = 0; i < N; i++) scanf("%s%d", name[i], card+i);
    build();
    int pos , kth = K-1, mn = N-tar;
    for(int n = N; n-- > mn; ){
        pos = q_modify(kth+1);//位置下标从必须开始0,这样才方便取模
        if(n){
            if(card[pos] > 0) card[pos]--; //可以看作往后移动一下,然后把kth去掉
            kth = (card[pos]+kth)%n;
            if(kth < 0) kth += n;
        }
    }
    printf("%s %d\n", name[pos], Fp[tar]+1);
    return 0;
}
线段树

12.8更新~

其实树状数组也可以logN的找到kth的, 就像猜数字一样不断缩小范围。

/*********************************************************
*            ------------------                          *
*   author AbyssalFish                                   *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
using namespace std;

const int MAX_N = 5e5+1, LEN = 11;

char name[MAX_N][LEN];
int card[MAX_N];


int N, K;

int C[MAX_N];

int q_Kth(int k)
{
    int p = 0, c = 0;
    for(int i = 19; i >= 0; i--){
        p += 1<<i;
        (p >= N || c + C[p] >= k)? p -= 1<<i : c += C[p];
    }
    return p+1;
}

void sub(int x)
{
    while(x <= N){
        C[x]--; x += x&-x;
    }
}



int Fp[MAX_N+1];



//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    //cout<<(1<<20);//ceil(log2(5e5)+1);
    scanf("%d%d",&N,&K);
    for(int i = 2; i <= N; i++){
        for(int j = i; j <= N; j += i){
            Fp[j]++;
        }
    }
    int tar = 1;
    for(int i = 2; i <= N; i++){
        if(Fp[tar] < Fp[i]) tar = i;
    }
    for(int i = 0; i < N; i++) scanf("%s%d", name[i], card+i);
    for(int i = 1; i <= N; i++) {
        C[i] = i&-i;
    }
    int pos , k = K-1, mn = N-tar;
    for(int n = N; n-- > mn; ){
        pos = q_Kth(k+1)-1; sub(pos+1);
        if(n){
            if(card[pos] > 0) card[pos]--;
            k = (card[pos]+k)%n;
            if(k < 0) k += n;
        }
    }
    printf("%s %d\n", name[pos], Fp[tar]+1);
    return 0;
}
树状数组

 

posted @ 2015-12-09 00:21  陈瑞宇  阅读(217)  评论(0编辑  收藏  举报