贪心问题 难度[普及-]一赏

目录

#小A的糖果
删数问题
陶陶摘苹果(升级版)
P5019 NOIP2018 提高组 铺设道路
混合牛奶 Mixing Milk
NOIP2007 普及组 纪念品分组
跳跳!


小A的糖果

原文链接:
P3817 小A的糖果 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

小 A 有 n 个糖果盒,第 i 个盒中有 a_i 颗糖果。

小 A 每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中糖的个数之和都不大于 x,至少得吃掉几颗糖。

输入格式

输入的第一行是两个用空格隔开的整数,代表糖果盒的个数 n 和给定的参数 x

第二行有 n 个用空格隔开的整数,第 i 个整数代表第 i 盒糖的糖果个数 a_i

输出格式

输出一行一个整数,代表最少要吃掉的糖果的数量。

样例 #1

样例输入 #1
3 3
2 2 2
样例输出 #1
1

样例 #2

样例输入 #2
6 1
1 6 1 2 0 4
样例输出 #2
11

样例 #3

样例输入 #3
5 9
3 1 4 1 5
样例输出 #3
0

提示

样例输入输出 1 解释

吃掉第 2 盒中的一个糖果即可。

样例输入输出 2 解释

第 2 盒糖吃掉 6 颗,第 4 盒吃掉 2 颗,第 6 盒吃掉 3 颗。

数据规模与约定

在这里插入图片描述

做题思想过程(菜)

#include <bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(0),cout.tie(0);cin.tie(0);
	int N,x,ans=0,chg;
	cin>>N>>x;
	int num[N];
	for (int i = 0; i < N; i++)
		cin>>num[i];
	for (int i = 1; i < N; i++)
	{
		if (num[i]+num[i-1]>x)
		{
			chg = num[i]+num[i-1]-x;
			num[i] -= chg;
			ans+= chg;
		}
	}
	cout<<ans;	
	return 0;
}

上述问题4个测试点没过

  • 原因一: 没开long long
    开了long long 再过俩
  • 原因二 : 没 考虑第一个首位
    e.g. 输入
3 10
9999 0 11

正确输出 9990 但是输出了9989 (给减成负数


删数问题

题目描述

键盘输入一个高精度的正整数 N N N(不超过 250 250 250 位),去掉其中任意 k k k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N N N k k k,寻找一种方案使得剩下的数字组成的新数最小。

输入格式

输入两行正整数。

第一行输入一个高精度的正整数 n n n

第二行输入一个正整数 k k k,表示需要删除的数字个数。

输出格式

输出一个整数,最后剩下的最小数。

样例 #1

样例输入 #1

175438 
4

样例输出 #1

13

#include <bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(0),cout.tie(0);cin.tie(0);
	string S;
	cin>>S;
	int k,i;
	cin>>k;
	while(k){
		if(S[0]=='0'){
			S.erase(0,1);
			continue;
		}	// 坑 删的时候怎么有0
		for (i=0;S[i]<S[i+1];)
		{i++;}
		S.erase(i,1);
		k--;
	} 
	while(S[0]=='0'&&S.length()>1)
		S.erase(0,1);
	cout<<S;
	return 0;
}
}

不会(一个点没过,搁置

陶陶摘苹果(升级版)

题目描述

又是一年秋季时,陶陶家的苹果树结了 n n n 个果子。陶陶又跑去摘苹果,这次他有一个 a a a 公分的椅子。当他手够不着时,他会站到椅子上再试试。

这次与 NOIp2005 普及组第一题不同的是:陶陶之前搬凳子,力气只剩下 s s s 了。当然,每次摘苹果时都要用一定的力气。陶陶想知道在 s < 0 s<0 s<0 之前最多能摘到多少个苹果。

现在已知 n n n 个苹果到达地上的高度 x i x_i xi,椅子的高度 a a a,陶陶手伸直的最大长度 b b b,陶陶所剩的力气 s s s,陶陶摘一个苹果需要的力气 y i y_i yi,求陶陶最多能摘到多少个苹果。

输入格式

1 1 1 行:两个数 苹果数 n n n,力气 s s s

2 2 2 行:两个数 椅子的高度 a a a,陶陶手伸直的最大长度 b b b

3 3 3 行~第 3 + n − 1 3+n-1 3+n1 行:每行两个数 苹果高度 x i x_i xi,摘这个苹果需要的力气 y i y_i yi

输出格式

只有一个整数,表示陶陶最多能摘到的苹果数。

样例 #1

样例输入 #1
8 15
20 130
120 3
150 2
110 7
180 1
50 8
200 0
140 3
120 2

样例输出 #1

4

提示

对于 100 % 100\% 100% 的数据, n ≤ 5000 n\leq 5000 n5000, a ≤ 50 a\leq 50 a50, b ≤ 200 b\leq 200 b200, s ≤ 1000 s\leq 1000 s1000, x i ≤ 280 x_i\leq 280 xi280, y i ≤ 100 y_i\leq 100 yi100


#include <bits/stdc++.h>
using namespace std;

struct Struct {
    int x, y;
};

bool cmp(const Struct& a, const Struct& b) {
    return a.y < b.y;
}

int main() {
    
    ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
    int n, s;
    cin >> n >> s;
    Struct ap[n];
    int a, b, x, y, f = 0;
    cin >> a >> b;
    for (int i = 0; i < n; i++) {
        cin >> x >> y;
        if (a + b >= x) {
            ap[f].x = x;
            ap[f].y = y;
            f++;
        }
    }
    sort(ap, ap + f, cmp);
    int i=0,ans=0;
	while(s){
		if(s>ap[i].y&&i<f){
			s-=ap[i].y;
			ans++;
			i++;
		}else
			break;
	}
	cout<<ans;
    return 0;
}

为什么不用桶排序…(上面的也没过

![#include <bits/stdc++.h>
using namespace std;

struct Struct {
    int x, y;
};
int to[300];
int main() {
    
    ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
    int n, s;
    cin >> n >> s;
    int a, b, x, y;
    cin >> a >> b;
    for (int i = 0; i < n; i++) {
        cin >> x >> y;
        if (a + b >= x) {
            to[y]++;
        }
    }
    int ans=0;
		for(int i=0;i<300;i++){
			while(to[i]>0&&s>i){
				s-=i;
				ans++;
				to[i]--;
			}
		}
	cout<<ans;
    return 0;
}

换桶排序了,还是第一个点没过
您猜怎么着,S=0,还有免费的苹果.
while(to[i]>0&&s>=i) 加上=即可


铺设道路

[P5019 NOIP2018 提高组] 铺设道路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

春春是一名道路工程师,负责铺设一条长度为 n n n 的道路。

铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 n n n 块首尾相连的区域,一开始,第 i i i 块区域下陷的深度为 d i d_i di

春春每天可以选择一段连续区间 [ L , R ] [L,R] [L,R] ,填充这段区间中的每块区域,让其下陷深度减少 1 1 1。在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为 0 0 0

春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变为 0 0 0

输入格式

输入文件包含两行,第一行包含一个整数 n n n,表示道路的长度。 第二行包含 n n n 个整数,相邻两数间用一个空格隔开,第 i i i 个整数为 d i d_i di

输出格式

输出文件仅包含一个整数,即最少需要多少天才能完成任务。

样例 #1

样例输入 #1
6   
4 3 2 5 3 5
样例输出 #1
9

提示

【样例解释】
一种可行的最佳方案是,依次选择:
[ 1 , 6 ] [1,6] [1,6] [ 1 , 6 ] [1,6] [1,6] [ 1 , 2 ] [1,2] [1,2] [ 1 , 1 ] [1,1] [1,1] [ 4 , 6 ] [4,6] [4,6] [ 4 , 4 ] [4,4] [4,4] [ 4 , 4 ] [4,4] [4,4] [ 6 , 6 ] [6,6] [6,6] [ 6 , 6 ] [6,6] [6,6]

【数据规模与约定】

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 10 1 ≤ n ≤ 10 1n10
对于 70 % 70\% 70% 的数据, 1 ≤ n ≤ 1000 1 ≤ n ≤ 1000 1n1000
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 100000 , 0 ≤ d i ≤ 10000 1 ≤ n ≤ 100000 , 0 ≤ d_i ≤ 10000 1n100000,0di10000


题解太强了(
题解一:贪心

#include<bits/stdc++.h>
using namespace std;
int n,a[100005];
long long ans=0;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)     cin>>a[i];
	/**/
	for(int i=2;i<=n;i++)     if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
	cout<<ans+a[1];   //+a[1]
	return 0;
}
//其实这个可以不用数组

题解二递推

#include<bits/stdc++.h>
using namespace std;
int n,a[110000],f[110000];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	f[1]=a[1];	//初始化
	for(int i=2;i<=n;i++)
	{
		if(a[i]<=a[i-1])
			f[i]=f[i-1];	//推
		else f[i]=f[i-1]+(a[i]-a[i-1]);  //后面比前面 *深* 时
	}
	cout<<f[n]<<endl;
	return 0;
}

混合牛奶

[USACO1.3]
from: P1208 [USACO1.3] 混合牛奶 Mixing Milk

题目描述

由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要。帮助 Marry 乳业找到最优的牛奶采购方案。

Marry 乳业从一些奶农手中采购牛奶,并且每一位奶农为乳制品加工企业提供的价格可能相同。此外,就像每头奶牛每天只能挤出固定数量的奶,每位奶农每天能提供的牛奶数量是一定的。每天 Marry 乳业可以从奶农手中采购到小于或者等于奶农最大产量的整数数量的牛奶。

给出 Marry 乳业每天对牛奶的需求量,还有每位奶农提供的牛奶单价和产量。计算采购足够数量的牛奶所需的最小花费。

注:每天所有奶农的总产量大于 Marry 乳业的需求量。

输入格式

第一行二个整数 n , m n,m n,m,表示需要牛奶的总量,和提供牛奶的农民个数。

接下来 m m m 行,每行两个整数 p i , a i p_i,a_i pi,ai,表示第 i i i 个农民牛奶的单价,和农民 i i i 一天最多能卖出的牛奶量。

输出格式

单独的一行包含单独的一个整数,表示 Marry 的牛奶制造公司拿到所需的牛奶所要的最小费用。

样例 #1

样例输入 #1
100 5
5 20
9 40
3 10
8 80
6 30
样例输出 #1
630

提示

【数据范围】
对于 100 % 100\% 100% 的数据:
0 ≤ n , a i ≤ 2 × 1 0 6 0 \le n,a_i \le 2 \times 10^6 0n,ai2×106 0 ≤ m ≤ 5000 0\le m \le 5000 0m5000 0 ≤ p i ≤ 1000 0 \le p_i \le 1000 0pi1000


这题写得如此顺畅( 可能已经熟练了,一次就过了 [肯定这是一道水题]

#include <bits/stdc++.h>
using namespace std;
struct milk_maker{
	int price,pnum;
};
bool cmp(const milk_maker&a ,const milk_maker&b){
	return a.price < b.price;
}
int main() {
    ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
    int n,m,ans=0;
    cin>>n>>m;
 	vector <milk_maker> milk(m);   
	for(int i=0;i<m;i++){
		cin>>milk[i].price>>milk[i].pnum;
	}
	sort(milk.begin(),milk.end(),cmp);	 
    while(n){
		for(int i=0;i<m;i++){
			if(n>=milk[i].pnum){
				ans+=milk[i].price*milk[i].pnum;
				n -=milk[i].pnum;
			}else {
				ans +=milk[i].price*n;
				n=0;
			}
		}
	}
	cout<<ans;
    return 0;
}

NOIP2007 普及组 纪念品分组

题目背景

NOIP2007 普及组 T2

题目描述

元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

输入格式

n + 2 n+2 n+2 行:

第一行包括一个整数 w w w,为每组纪念品价格之和的上限。

第二行为一个整数 n n n,表示购来的纪念品的总件数 G G G

3 ∼ n + 2 3\sim n+2 3n+2 行每行包含一个正整数 P i P_i Pi 表示所对应纪念品的价格。

输出格式

一个整数,即最少的分组数目。

样例 #1

样例输入 #1
100 
9 
90 
20 
20 
30 
50 
60 
70 
80 
90
样例输出 #1
6

提示

50 % 50\% 50% 的数据满足: 1 ≤ n ≤ 15 1\le n\le15 1n15
100 % 100\% 100% 的数据满足: 1 ≤ n ≤ 3 × 1 0 4 1\le n\le3\times10^4 1n3×104 80 ≤ w ≤ 200 80\le w\le200 80w200 5 ≤ P i ≤ w 5 \le P_i \le w 5Piw


代码
排序,左右加,
顺畅得一会儿上大号,看看大号是不是也顺畅
贪心感觉思路对了,代码很好写(

#include <bits/stdc++.h>
using namespace std;
bool cmp(int &a,int &b){
	return a < b;
}
int main() {
    ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
    int w,ans=0;
    cin>>w;
    int n;
    cin>>n;
    vector<int> price(n);
    for(int i=0;i<n;i++)
		cin>>price[i];
	sort(price.begin(),price.end(),cmp); 
	int l=0,r=n-1;
	while(l<r){
		if(price[r]+price[l]>w){
			r--;
			ans++;
		}else{
			int sum=price[r]+price[l];
			r--;
			l++;
			while(sum+price[l]<w)
				l++;
			ans++;		
		} 
	}
	if(l==r){
		ans++;
	}
	cout<<ans;
    return 0;
}

跳跳!

题目描述

你是一只小跳蛙,你特别擅长在各种地方跳来跳去。

这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i i i 块的石头高度为 h i h_i hi,地面的高度是 h 0 = 0 h_0 = 0 h0=0。你估计着,从第 i i i 块石头跳到第 j j j 块石头上耗费的体力值为 ( h i − h j ) 2 (h_i - h_j) ^ 2 (hihj)2,从地面跳到第 i i i 块石头耗费的体力值是 ( h i ) 2 (h_i) ^ 2 (hi)2

为了给小 F 展现你超级跳的本领,你决定跳到每个石头上各一次,并最终停在任意一块石头上,并且小跳蛙想耗费尽可能多的体力值。

当然,你只是一只小跳蛙,你只会跳,不知道怎么跳才能让本领更充分地展现。

不过你有救啦!小 F 给你递来了一个写着 AK 的电脑,你可以使用计算机程序帮你解决这个问题,万能的计算机会告诉你怎么跳。

那就请你——会写代码的小跳蛙——写下这个程序,为你 NOIp AK 踏出坚实的一步吧!

输入格式

输入一行一个正整数 n n n,表示石头个数。

输入第二行 n n n 个正整数,表示第 i i i 块石头的高度 h i h_i hi

输出格式

输出一行一个正整数,表示你可以耗费的体力值的最大值。

样例 #1

样例输入 #1
2
2 1
样例输出 #1
5

样例 #2

样例输入 #2
3
6 3 5
样例输出 #2
49

提示

样例解释

两个样例按照输入给定的顺序依次跳上去就可以得到最优方案之一。

数据范围

对于 1 ≤ i ≤ n 1 \leq i \leq n 1in,有 0 < h i ≤ 1 0 4 0 < h_i \leq 10 ^ 4 0<hi104,且保证 h i h_i hi 互不相同。
对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n3
对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n10
对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n20
对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n50
对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n300


从地上左右来回蹦跶即可(
卡shi了(坏)
50分,该罚
原因: “不开long long 见祖宗”

#include <bits/stdc++.h>
using namespace std;
bool cmp(long long &a,long long &b){
	return a < b;
}
int main() {
    ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
    long long n;
    cin>>n;
    vector<long long> h(n);
    for(int i=0;i<n;i++){
		cin>>h[i];
	}
	sort(h.begin(),h.end(),cmp);
	long long l=0,r=n-1,ans=0,now=0;
	while(r>=l){
		ans += pow(h[r]-now,2); 
		now= h[r];
		r--;
		ans += pow(h[l]-now,2);
		now= h[l];
		l++;
	}
	cout<<ans;
    return 0;
}

害(
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值