暑假每日算法学习打卡(六)----[CQOI2009]中位数图,货物种类(牛客)

1.[CQOI2009]中位数图

题目描述 
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
输入描述:
第一行为两个正整数n和b ,第二行为1~n 的排列。
输出描述:
输出一个整数,即中位数为b的连续子序列个数。
示例1
输入
复制
7 4
5 7 2 4 3 1 6
输出
复制
4
备注:
对于30%的数据中,满足 n \le 100n≤100;

对于60%的数据中,满足 n \le 1000n≤1000;

对于100%的数据中,满足 n \le 100000,1 \le b \le nn≤100000,1≤b≤n。

思路:注意题目上说的奇数连续子序列包括1个,只取它自己;找中位数,就是要取出的序列排序后它刚好在最中间,我们可以忽略具体数值,将比中位数大的数存为1,比它小的存为-1,因为是序列,无重复数据,再记录下中位数的位置,求出后缀和,前缀和;取出的子序列有三种情况,中位数向左取或向右取,或者两边都含有,前缀和为零+后缀和为零+(前缀和+后缀和=0)就是符合要求的子序列;

AC代码:

#include <iostream>

using namespace std;
int a[100001],num[100001];
int main()
{
    int n,b,c,k;
    cin>>n>>b;
    for(int i=1;i<=n;i++)
    {
        cin>>c;
        if(c<b)
            a[i]=-1;
        else if(c==b)
            k=i;
        else a[i]=1;
    }
     int sum=0,count=0;
     for(int i=k-1;i>0;i--)
     {
         sum+=a[i];
         num[i]=sum;
         if(sum==0)
            count++;
     }
     sum=0;
     for(int i=k+1;i<=n;i++)
     {
         sum+=a[i];
         num[i]=sum;
         if(sum==0)
            count++;
            for(int j=k-1;j>0;j--)
               if(num[i]+num[j]==0)
                    count++;

     }
     cout<<count+1;
    return 0;
}

2. 货物种类
题目描述

某电商平台有n个仓库,编号从1到n。

当购进某种货物的时候,商家会把货物分散的放在编号相邻的几个仓库中。

我们暂时不考虑售出,你是否能知道,当所有货物购买完毕,存放货物种类最多的仓库编号为多少?

输入描述:

在第一行中给出两个正整数n,m,1≤n,m≤105n, m, 1\le n, m \le 10^5n,m,1≤n,m≤105,分别代表仓库的数目和进货的次数。

接下来 m 行,每行三个正整数l,r,d,1≤l,r≤n,1≤d≤109l,r,d,1 \le l,r \le n, 1 \le d \le 10^9l,r,d,1≤l,r≤n,1≤d≤109。编号在l和r之间的仓库收进编号为d的货物。

(包括l和r)

输出描述:

在一行中输出存放货物种类最多的仓库编号,若满足条件的仓库不止一个,则输出编号最小的那个。

示例1

输入

5 5
1 1 1
3 3 1
2 5 2
5 5 1
4 5 1

输出

3

思路:本来想暴力一点,用每输入一组区间和货物就给区间赋相应的货物编号;但是出现问题,重复时就有问题像1 3 1;2 3 2;3 3 1;就不对了;后来用结构体储存区间左右端点和货物编号,然后对货物编号相同的数据按区间排序,遍历合并区间统计区间内货物种类

#include<iostream>
#include<algorithm>
using namespace std;
int b[100001];
struct f
{
  int l,r,d;
}s[100001];
bool comp(f a,f b)
{
    if(a.d==b.d) return a.l<b.l;
    return a.d<b.d;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int j=1;j<=m;j++)
    {
        cin>>s[j].l>>s[j].r>>s[j].d;
    }
    sort(s+1,s+m+1,comp);
    int row=s[1].r,le=s[1].l;
    for(int i=2;i<=m;i++)
    {
        if(row>=s[i].l&&s[i].d==s[i-1].d)
        {
            row=max(row,s[i].r);
        }else
        {
         b[le]++,b[row+1]--;row=s[i].r,le=s[i].l;
        }
    }
    b[le]++;b[row+1]--;
    int maxn=0,sum=0,k;
    for(int i=1;i<=n;i++)
    {
        sum+=b[i];
        //cout<<sum<<" ";
        if(sum>maxn)
        {
            maxn=sum;
            k=i;
        }
    }
    cout<<k;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值