HDU4908 - BestCoder Sequence(BestCoder Round #3 计数)

题目链接 HDU4908

【题意】在1~n的一个排列中找到以m为中位数的连续子序列有多少个。

【分析】先求出sum[i][j],表示左边序列长度(不算m)为奇数或者偶数(j表示奇偶)的时候 大于m个数-小于m个数 的序列个数。
然后遍历m右边长度为奇数个(这时整个序列是奇数个 奇数+奇数+1 = 奇数 或者 偶数+偶数+1 = 奇数)时
小于m-大于m 的个数s时,累加上所有sum[小于m个数-大于m个数][()&1];
因为 左边大于m的数的个数b1+右边大于m的个数b2 = 左边小于m的个数s1+右边小于m的个数s2
这正是当遍历右边的时候 右边小于m个数s2-右边大于m个数b2 = 左边大于m个数b1-左边小于m个数s1(上式移项得到)

 

【AC CODE】 78ms

#include <cstdio>
#include <cstring>
#define MAXN 40000
int a[MAXN+10], sum[2*MAXN+10][2];
//sum[i][j]表示左边序列长度(不算m)为奇数或者偶数(j表示奇偶)的时候 大于m个数-小于m个数 的序列个数,
/*然后遍历m右边长度为奇数个(这时整个序列是奇数个 奇数+奇数+1 = 奇数 或者 偶数+偶数+1 = 奇数)时
小于m-大于m 的个数s时,累加上所有sum[小于m个数-大于m个数][()&1];
因为 左边大于m的数的个数b1+右边大于m的个数b2 = 左边小于m的个数s1+右边小于m的个数s2
这正是当遍历右边的时候 右边小于m个数s2-右边大于m个数b2 = 左边大于m个数b1-左边小于m个数s1(上式移项得到)*/

int main()
{
#ifdef SHY
    freopen("e:\\1.txt","r",stdin);
#endif
    int n,m;
    while(~scanf("%d %d%*c", &n, &m))
    {
        int ans, mid, p = 0;
        memset(sum,0,sizeof(sum));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%*c", &a[i]);
            if(m == a[i]) mid = i;
        }
		sum[MAXN][0] = 1;//只有一个m的时候
        for(int i = mid-1; i >= 1; i--)
        {
            if(a[i] > m) p++;
			else p--;
			sum[p+MAXN][(mid-i)&1]++;
        }
		p = 0;
		ans = sum[MAXN][0];//先加上所有p为0时的偶数个序列
        for(int i = mid+1; i <= n; i++)
        {
			if(a[i] > m) p--;
			else p++;
			ans += sum[p+MAXN][(i-mid)&1];
        }
        printf("%d\n", ans);
    }
    return 0;
}


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值