[BestCoder] Round #3 1001、1002 | HDU 4907、4908

 [HDU 4907]  1001.Task schedule

中文题目,根据ti直接倒着预处理一次,就可以了。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#define INF 10
typedef long long LL;
using namespace std;
int a[200001], b[200002];
int main()
{
    int t, n, m;
    scanf("%d", &t);
    while(t--)
    {
        memset(b, 0, sizeof(b));
        scanf("%d %d", &n, &m);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            b[a[i]] = 1;
        }
        for(int i = 200001; i >= 0; i--)
        {
            if(b[i] == 0)
            {
                 flag = i;
            }
            a[i] = flag;
        }
        for(int i = 0; i < m; i++)
        {
            int temp;
            scanf("%d", &temp);
            printf("%d\n", a[temp]);
        }
    }
    return 0;
}


 [HDU 4908]  1002.BestCoder Sequence

题意是求中位数是M的一个子序列的个数。

看下数据规模,暴力是行不通的。比赛的时候没写完。。。

首先根据中位数的定义可知,当一个序列中,大于M的数字个数 等于 小于M的数字个数的时候,M一定是中位数。

也就是一个序列中,大于M的数字个数 - 小于M的数字个数 = 0,这个序列的中位数才能是M。

那我们就可以通过递推,分别统计M左右 大于M的数字个数 - 小于M的数字个数。

举个例子:

一个子序列,如果中位数是M,并且M左面如果 大于M的数字个数 - 小于M的数字个数 = 1,那么M右面 大于M的数字个数 - 小于M的数字个数 一定等于-1。

也就是左右的和保证平衡。

然后,用数组标记把左右的差值存起来,由于有负数,标记的时候需要把负数右移为正数进行标记。

我们枚举左右其中一面,就可以解决了,复杂度降低了。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#define INF 40000
typedef __int64 LL;
using namespace std;
int main()
{
	int n, m, a[50000], b[100000], c[100000], d[100000], flag;
	LL ans;
    while(~scanf("%d %d", &n, &m))
    {
    	ans = 0;
    	memset(b, 0, sizeof(b));
    	memset(c, 0, sizeof(c));
    	for(int i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);
			if(a[i] == m)
			{
				flag = i;
			}
		}
		d[flag] = 0;
		for(int i = flag-1; i >= 0; i--)
		{
			if(a[i] > a[flag])			 
			{
				d[i] = d[i+1] - 1;
			}							/*递推求M左面 大于M的数字个数-小于M的数字个数*/
			else
			{
				d[i] = d[i+1] + 1;
			}
			++b[d[i]+INF];				//把左面 大于M的数字个数-小于M的数字个数 存到数组标记
		}
		for(int i = flag+1; i < n; i++)
		{
			if(a[i] > a[flag])			 
			{
				d[i] = d[i-1] - 1;
			}
			else						//递推求M右面 大于M的数字个数-小于M的数字个数
			{
				d[i] = d[i-1] + 1;
			}
			++c[d[i]+INF];				//把M右面 大于M的数字个数-小于M的数字个数 存到数组标记 
		}
		for(int i = 0; i < 80001; i++)
		{
			if(c[i] && b[INF+INF-i])
			{
				ans += (LL)c[i] * b[INF+INF-i]; 
			}
		}
		printf("%I64d\n", ans + 1 + b[INF] + c[INF]);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值