『比赛』2016"百度之星" - 初赛(Astar Round2B)1006

中位数计数

转载声明:http://blog.csdn.net/jtjy568805874/article/details/51477656
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5701

个人想法:这次是我第一次写得博客,在平时我几乎没写过博客,我突然觉得写博客很重要,这是一个我的错题集,我想把我的想法分享给大家,平时也看到一些题解,完全就是粘贴的,说得不明不白,感觉和没写一样,这好没意思哦.所以我也想分享我做题过程.首先一开始我是想用划分树来写的,因为查询中位数用划分树就logn左右,只要枚举奇数的范围区间中的中位数就可以得到对应中位数的个数,然后再加n^2/2的循环,按道理应该不会超时,可是毫无意外的还是超时了,然后听到同学统计左右区间的比当前的数大的和小的个数就好了…可是我做了还是超时,然后,就没有然后了,实在想不到优化. 这是我转载的一个声明,实在是狠狠打了自己一巴掌,自己实在太蠢了…这也想不出来.╮(╯▽╰)╭。

分析:这题的意思是找到每个数在连续区间中作为中位数的次数,其实做一次题目样例就可以发现只需要统计奇数区间就行了,并不存在偶数区间的统计,偶数的统计还得获得两个数再做平均,这显然不是题目本意,好了我们可以向到枚举每个区间的中位数就好了,假设我当前的数是a[i],然后我算下一个是比a[i]大还是小,用个数组rmax[i]||rmin[i]记录下来, 然后扫描a[i]的左区间,同样的,用数组lmax[i],lmin[i] 记录下来,直接lmin[i]+rmin[i]==rmax[i]+lmax[i] ans就加一,然后继续往右拓展,记录再下一个数是大还是小,再往左扫描,可是显然这样子是会超时的,这几乎是n3的算法,从我看了这博客之后我就发现了一个问题!!重复计算!!,因为在往右扫面的时候,其实rmax[i]-rmin[i]=x是变化 而且会重复出现次数,只要我扫面一编a[i]右边的值,然后就知道右边位置需要大的个数和小的个数就多少,然后扫面左边的时候,和右边做个叠加就好了,因为这是个偏离中位数的思想,这里有点点说不清,具体看一下代码就应该大概明白了.

代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
int N;
int Pian[20000];
int Num[8005];
int main()
{
#ifdef OUT
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    while(scanf("%d",&N)!=EOF)
    {
         bool flag=true;
         for(int i=1;i<=N;i++)
         {
             scanf("%d",&Num[i]);
         }
         for(int i=1;i<=N;i++)
         {
             memset(Pian,0,sizeof(Pian));

             int x=0;
             Pian[8005+x]++;
             for(int j=1;(i+j)<=N;j++)
             {
                 if(Num[i+j]>Num[i])x++;
                 else x--;
                 Pian[8005+x]++;//这就是左边偏离重复的统计
             }

             x=0;
             int ans=Pian[8005];//先把右边的没偏离的加上,虽然看了点blog,大概思想有了,但是还是写错,忘记先统计右边,wa很多次。
             for(int j=1;(i-j)>=1;j++)
             {
                 if(Num[i-j]>Num[i])x++;
                 else x--;
                 ans+=Pian[8005-x];//然后把左边缺少相应的个数向右边拍过去,那就是答案.
             }
             if(flag){printf("%d",ans);flag=false;}
             else printf(" %d",ans);

         }
         printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值