区间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;
}