蓝桥算法训练 区间k大数查询 快乐司机 剪格子

区间k大数查询

题目:

问题描述

给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。

输入格式

第一行包含一个数n,表示序列长度。

第二行包含n个正整数,表示给定的序列。

第三个包含一个正整数m,表示询问个数。

接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。

输出格式

总共输出m行,每行一个数,表示询问的答案。

样例输入

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

样例输出

4
2

数据规模与约定

对于30%的数据,n,m<=100;

对于100%的数据,n,m<=1000;

保证k<=(r-l+1),序列中的数<=106。

 

题目分析:

题意很简单,就是先给一组序列,然后给定一个区间,寻找在这个小区间内,第k个最大的数是多少?

自己刚开始做时,只简单地想到了,每输入一个区间,就把这个区间从原区间中摘出来,对它进行排序,进而寻找第k大数,但是自己忽略了一个问题,从第一次给小区间排序后,原区间内数的顺序就已经改变了,接下来每输入一次,就又改变一次。

所以,可以添加一个b数组,把a数组的值赋值给b数组,每次摘出小区间排序时都对b数组进行操作。在对下一组数据进行操作时,再将a数组的值赋给b数组,再对b数组进行操作。

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    int n, m, a[1010], b[1010];
    int l,r,k;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int j=1;j<=m;j++)
        {
            scanf("%d%d%d",&l,&r,&k);
            for(int i=1;i<=n;i++)
               b[i]=a[i];
            sort(b+l,b+r+1,cmp);
            printf("%d\n",b[l-1+k]);
        }
    }
    return 0;
}

 

快乐司机

题目:

问题描述

  "嘟嘟嘟嘟嘟嘟
  喇叭响
  我是汽车小司机
  我是小司机
  我为祖国运输忙
  运输忙"
  这是儿歌“快乐的小司机”。话说现在当司机光有红心不行,还要多拉快跑。多拉不是超载,是要让所载货物价值最大,特别是在当前油价日新月异的时候。司机所拉货物为散货,如大米、面粉、沙石、泥土......
  现在知道了汽车核载重量为w,可供选择的物品的数量n。每个物品的重量为gi,价值为pi。求汽车可装载的最大价值。(n<10000,w<10000,0<gi<=100,0<=pi<=100)

输入格式

  输入第一行为由空格分开的两个整数n w
  第二行到第n+1行,每行有两个整数,由空格分开,分别表示gi和pi

输出格式

  最大价值(保留一位小数)

样例输入

5 36
99 87
68 36
79 43
75 94
7 35

样例输出

71.3
解释:
先装第5号物品,得价值35,占用重量7
再装第4号物品,得价值36.346,占用重量29
最后保留一位小数,得71.3

题目分析:这题就是一个数学问题,给出n种物品,给出每种物品的体积与价值,自己所能接受的体积是有限的,问怎样选择能使价值最高。从案例可以看出,每种物品不需要全拿,物品可以只要一部分,所以求出每种物品1体积对应的价值量是多少,优先选择价值量高的,直到装满所给出的体积。

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{

     double g,p,m;//
}P[10010];
bool cmp(node a,node b)
{
    return a.m>b.m;//注意这里进行排序的是哪个量
}
int main()
{
    int n,w;
    while(scanf("%d%d",&n,&w)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&P[i].g,&P[i].p);
            P[i].m=P[i].p/P[i].g;//每体积对应的价值
        }
         sort(P,P+n,cmp);
         double sum=0;
         for(int i=0;i<n;i++)
         {
             if(w>0)
             {
                if(w-P[i].g>=0)
                {
                   sum=sum+P[i].p;
                   w-=P[i].g;
                }
                else if(w<P[i].g)
                {


                    sum+=w*P[i].m;
                    w-=w;

                }
             }
         }
         printf("%.1lf\n",sum);
    }
    return 0;
}

 

 

剪格子 

题目:

问题描述

如下图所示,3 x 3 的格子中填写了一些整数。

+--*--+--+
|10* 1|52|
+--****--+
|20|30* 1|
*******--+
| 1| 2| 3|
+--+--+--+

我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。

如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。

如果无法分割,则输出 0。

输入格式

程序先读入两个整数 m n 用空格分割 (m,n<10)。

表示表格的宽度和高度。

接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000。

输出格式

输出一个整数,表示在所有解中,包含左上角的分割区可能包含的最小的格子数目。

样例输入1

3 3
10 1 52
20 30 1
1 2 3

样例输出1

3

样例输入2

4 3
1 1 1 1
1 30 80 2
1 1 1 100

样例输出2

10

题目分析:这里用的知识是搜索

首先,先将所有的数加起来,判断最后的值是不是偶数,如果不是,一定不能将这些数,平均的分为两部分。如果是,用dfs进行搜索,终止条件是找的数累加起来等于总和的一半。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int m,n,sum;
int a[11][11],vis[11][11];
int go[4][2]={1,0,-1,0,0,1,0,-1 };
int dfs(int x,int y,int num)
{
    if(num==sum/2) return 1;
    for(int i=0;i<4;i++)
    {
        int nx=x+go[i][0];
        int ny=y+go[i][1];
        if(nx<0 || ny<0 || nx>=n || ny>=m  || vis[nx][ny] || (num + a[nx][ny] > sum/2)  )
            continue;
        vis[nx][ny] = 1;
        int sm = dfs(nx,ny,num+a[nx][ny]);
        if(sm)
            return sm+1;
        vis[nx][ny] =0;
    }
    return 0;
}
int main()
{
   while(scanf("%d%d",&m,&n)!=EOF)
   {
       sum=0;
       for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
       {
           scanf("%d",&a[i][j]);
           sum+=a[i][j];
       }
       if(sum%2) printf("0\n");
        else
        {
            memset(vis,0,sizeof(vis));
            vis[0][0]=1;
            printf("%d\n",dfs(0,0,a[0][0]));
        }

   }
    return 0;
}

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值