FZU2288 谁还不是个宝宝 福州大学第十五届程序设计竞赛E题

 

Problem 2288 谁还不是个宝宝

Accept: 4    Submit: 9
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

洪尼玛有n个朋友,n个朋友排成一排,每个朋友都有一个自身的价值Ai,并且每个朋友自身的价值均不相同。现在每个朋友都能与他左右的若干个人组成一个区间,也可以他自己一个人组成一个区间。若这个区间的人数为奇数个,那么我们称其为“可行区间”。将一个 “可行区间”里所有朋友按价值排序后,中间的那个朋友就是这个“可行区间”里的“宝宝”。求每个朋友是多少个“可行区间”里的“宝宝”?

 Input

多组测试数据。

输入第一行为正整数n,表示朋友个数。

接下来一行,有n个互不相同的正整数Ai,表示第i个朋友的价值。

n≤1000,Ai≤10^9

 Output

输出n个正整数,依次表示第i个朋友是多少个“可行区间”里的“宝宝”。

 Sample Input

5 1 2 3 4 5

 Sample Output

1 2 3 2 1

 Hint

例如3能组成的“可行间”有:{3},{1,2,3},{2,3,4},{3,4,5},{1,2,3,4,5} 共5个区间,其中在{3},{2,3,4},{1,2,3,4,5} 这3个“可行区间”里是宝宝。

 Source

福州大学第十五届程序设计竞赛_重现赛

 

Submit  Back  Status  Discuss

 

【题目链接】http://acm.fzu.edu.cn/problem.php?pid=2288

 

【思路】用两个优先队列维护大顶堆和小顶堆,小顶堆中放比a[mid]小的元素,大顶堆中放比a[mid]大的元素,每次通过比较两个队列的大小来求解mid元素。每次先把mid和a[mid] push进size比较大的一个队列中去,然后通过pop 和 push操作使得当前两个队列的size相差为1,最后size较大的队列的队首元素就是新的mid。

【时间复杂度】n*(logn)^2

【代码如下】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

int a[2100],n,cnt[2100];
struct node{
    int indx,num;
    node(int x, int y):indx(x),num(y){}
    friend bool operator<(node A, node B){ //大顶堆
        return A.num < B.num;
    }
};
struct Node{
    int indx,num;
    Node(int x, int y):indx(x),num(y){}
    friend bool operator<(Node A, Node B){ //小顶堆
        return A.num > B.num;
    }
};

int main(){
    while(~scanf("%d",&n)){
        for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);
        memset(cnt,0,sizeof(cnt));//cnt[i]统计下标为i的元素符合条件的答案
        for(int i = 1; i <= n; i ++){
            priority_queue<node>pqa;//大顶堆维护队列
            priority_queue<Node>pqb;//小顶堆维护队列
            int mid=-1,siza=0,sizb=0;
            for(int j = i; j <= n; j += 2){
                if(mid==-1) {mid=j;cnt[mid]++; continue;}
                else{
                    int l=j-1,r=j;
                    if(a[l]<a[mid]) pqa.push(node(l,a[l])),siza++;
                    else pqb.push(Node(l,a[l])),sizb++;
                    if(a[r]<a[mid]) pqa.push(node(r,a[r])),siza++;
                    else pqb.push(Node(r,a[r])),sizb++;
                }
                if(siza==sizb) cnt[mid]++;
                else{
                    int flag=0;
                    if(siza>sizb) pqa.push(node(mid,a[mid])),siza++,flag=1;
                    while(siza-1>sizb){
                        node no = pqa.top(); pqb.push(Node(no.indx,no.num));
                        pqa.pop();
                        siza--; sizb++;
                    }
                    if(siza<sizb) pqb.push(Node(mid,a[mid])),sizb++,flag=2;
                    while(siza<sizb-1){
                        Node no=pqb.top(); pqa.push(node(no.indx,no.num));
                        pqb.pop();
                        siza++; sizb--;
                    }
                    if(flag==1){
                        node no = pqa.top(); mid = no.indx; pqa.pop(); siza--;
                    }
                    else if(flag==2){
                        Node no = pqb.top(); mid = no.indx; pqb.pop(); sizb--;
                    }
                    cnt[mid] ++;
                }
            }
        }
        for(int i = 1; i <= n; i ++){
            if(i>1) printf(" ");
            printf("%d",cnt[i]);
        }
        printf("\n");
    }
    return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值