Part2.5贪心

贪心,指的是决策时都采取当前最优解的算法。有的时候,这样做确实可以获得最优解。

[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

题目翻译来自 NOCOW。

USACO Training Section 1.3

代码实现

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 2000000
#define MAX_M 5000
typedef struct Data{
	int p,a;
};
bool cmp(Data&a,Data&b)
{
	return a.p<b.p;
}
Data farmer[MAX_M+5];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	cin>>farmer[i].p>>farmer[i].a;
	sort(farmer+1,farmer+1+m,cmp);
	int now=0,money=0;
	for(int i=1;i<=m;i++)
	{
		if(now+farmer[i].a<n)
		{
			money+=farmer[i].a*farmer[i].p;
			now+=farmer[i].a;
		}
		else{
			money+=(n-now)*farmer[i].p;
			break;
		}
	}
	cout<<money;
	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

代码实现

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 300
long long a[MAX_N+5];
int main()
{
	long long ans=0;
	int n;
	cin>>n;
	a[1]=0;
	for(int i=2;i<=n+1;i++)cin>>a[i];
	sort(a+1,a+n+2);
	int i=1,j=n+1;
	int flag=1;
	while(i<j)
	{
		ans+=(a[j]-a[i])*(a[j]-a[i]);
		if(flag)
		{
			i++;
			flag=0;
		}
		else{
			j--;
			flag=1;
		}
	}
	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<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 30000
bool cmp(int a,int b)
{
	return a>b;
}
int a[MAX_N+5];
int main()
{
	int w,n;
	cin>>w>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+n+1,cmp);
	int i=1,j=n,cnt=0;
	while(i<j)
	{
		cnt+=1;
		if(a[i]+a[j]<=w)i++,j--;
		else i++;
	}
	if(i==j)cnt++;
	cout<<cnt;
	return 0;
	
}

[NOIP2010 普及组] 三国游戏

题目描述

小涵很喜欢电脑游戏,这些天他正在玩一个叫做《三国》的游戏。

在游戏中,小涵和计算机各执一方,组建各自的军队进行对战。游戏中共有 N N N 位武将( N N N 为偶数且不小于 4 4 4),任意两个武将之间有一个“默契值”,表示若此两位武将作为一对组合作战时,该组合的威力有多大。游戏开始前,所有武将都是自由的(称为自由武将,一旦某个自由武将被选中作为某方军队的一员,那么他就不再是自由武将了),换句话说,所谓的自由武将不属于任何一方。

游戏开始,小涵和计算机要从自由武将中挑选武将组成自己的军队,规则如下:小涵先从自由武将中选出一个加入自己的军队,然后计算机也从自由武将中选出一个加入计算机方的军队。接下来一直按照“小涵 → \to 计算机 → \to 小涵 → … \to\dots ”的顺序选择武将,直到所有的武将被双方均分完。然后,程序自动从双方军队中各挑出一对默契值最高的武将组合代表自己的军队进行二对二比武,拥有更高默契值的一对武将组合获胜,表示两军交战,拥有获胜武将组合的一方获胜。

已知计算机一方选择武将的原则是尽量破坏对手下一步将形成的最强组合,它采取的具体策略如下:任何时刻,轮到计算机挑选时,它会尝试将对手军队中的每个武将与当前每个自由武将进行一一配对,找出所有配对中默契值最高的那对武将组合,并将该组合中的自由武将选入自己的军队。 下面举例说明计算机的选将策略,例如,游戏中一共有 6 6 6个武将,他们相互之间的默契值如下表所示:

武将编号123456
1 5 5 5 28 28 28 16 16 16 29 29 29 27 27 27
2 5 5 5 23 23 23 3 3 3 20 20 20 1 1 1
3 28 28 28 23 23 23 8 8 8 32 32 32 26 26 26
4 16 16 16 3 3 3 8 8 8 33 33 33 11 11 11
5 29 29 29 20 20 20 32 32 32 33 33 33 12 12 12
6 27 27 27 1 1 1 26 26 26 11 11 11 12 12 12

双方选将过程如下所示:

小涵轮到计算机时可选的自由武将计算机计算机选将说明
第一轮 5 5 5 1 , 2 , 3 , 4 , 6 1,2,3,4,6 1,2,3,4,6 4 \color{magenta}4 4小涵手中的 5 5 5 号武将与 4 4 4 号的默契值最高,所以计算机选择 4 4 4 号。
第二轮 5 , 3 5,3 5,3 1 , 2 , 6 1,2,6 1,2,6 4 , 1 4,\color{magenta}1 4,1小涵手中的 5 5 5 号和 3 3 3 号武将与自由武将中配对可产生的最大默契值为 29 29 29,是由 5 5 5 号与 1 1 1 号配对产生的,所以计算机选择 1 1 1 号。
第三轮 5 , 3 , 6 5,3,6 5,3,6 2 2 2 4 , 1 , 2 4,1,\color{magenta}2 4,1,2

小涵想知道,如果计算机在一局游戏中始终坚持上面这个策略,那么自己有没有可能必胜?如果有,在所有可能的胜利结局中,自己那对用于比武的武将组合的默契值最大是多少?

假设整个游戏过程中,对战双方任何时候均能看到自由武将队中的武将和对方军队的武将。为了简化问题,保证对于不同的武将组合,其默契值均不相同。

输入格式

N N N 行。

第一行为一个偶数 N N N,表示武将的个数。

2 2 2 行到第 N N N 行里,第 i + 1 i+1 i+1 行有 N − i N-i Ni 个非负整数,每两个数之间用一个空格隔开,表示 i i i 号武将和 $i+1,i+2,\dots,N $ 号武将之间的默契值( 0 ≤ 默契值 ≤ 1 0 9 0≤\text{默契值}\le10^9 0默契值109)。

输出格式

共一或二行。

若对于给定的游戏输入,存在可以让小涵获胜的选将顺序,则输出 $ 1$,并另起一行输出所有获胜的情况中,小涵最终选出的武将组合的最大默契值。如果不存在可以让小涵获胜的选将顺序,则输出 0 0 0

样例 #1

样例输入 #1

6 
5 28 16 29 27 
23 3 20 1 
8 32 26 
33 11 
12

样例输出 #1

1
32

样例 #2

样例输入 #2

8 
42 24 10 29 27 12 58 
31 8 16 26 80 6 
25 3 36 11 5 
33 20 17 13 
15 77 9 
4 50 
19

样例输出 #2

1
77

提示

数据范围

对于 $ 40%$ 的数据有 N ≤ 10 N≤10 N10

对于 $ 70%$ 的数据有 $ N≤18$。

对于 100 % 100\% 100% 的数据有 4 ≤ N ≤ 500 4\le N≤500 4N500。保证对于不同的武将组合,其默契值均不相同。

NOIP2010 普及组 第四题

代码实现

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 500
int a[MAX_N+5][MAX_N+5]={0};
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			cin>>a[i][j];
			a[j][i]=a[i][j];
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		sort(a[i]+1,a[i]+1+n);
		ans=ans<a[i][n-1]?a[i][n-1]:ans;
	}
	cout<<"1"<<endl<<ans;
	return 0;
}

[NOIP2015 普及组] 推销员

题目背景

NOIP2015 普及组 T4

题目描述

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有 N N N 家住户,第 i i i 家住户到入口的距离为 S i S_i Si 米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的 X X X 家住户推销产品,然后再原路走出去。

阿明每走 1 1 1 米就会积累 1 1 1 点疲劳值,向第 i i i 家住户推销产品会积累 A i A_i Ai 点疲劳值。阿明是工作狂,他想知道,对于不同的 X X X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

输入格式

第一行有一个正整数 N N N,表示螺丝街住户的数量。

接下来的一行有 N N N 个正整数,其中第 i i i 个整数 S i S_i Si 表示第 i i i 家住户到入口的距离。数据保证 S 1 ≤ S 2 ≤ ⋯ ≤ S n < 1 0 8 S_1 \le S_2 \le \cdots \le S_n <10^8 S1S2Sn<108

接下来的一行有 N N N 个正整数,其中第 i i i 个整数 A i A_i Ai 表示向第 i i i 户住户推销产品会积累的疲劳值。数据保证 A i < 1000 A_i<1000 Ai<1000

输出格式

输出 N N N 行,每行一个正整数,第 i i i 行整数表示当 X = i X=i X=i 时,阿明最多积累的疲劳值。

样例 #1

样例输入 #1

5
1 2 3 4 5
1 2 3 4 5

样例输出 #1

15
19
22
24
25

样例 #2

样例输入 #2

5
1 2 2 4 5
5 4 3 4 1

样例输出 #2

12
17
21
24
27

提示

输入输出样例 1 说明

X = 1 X=1 X=1:向住户 5 5 5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值为 5 5 5,总疲劳值为 15 15 15

X = 2 X=2 X=2:向住户 4 , 5 4,5 4,5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值为 4 + 5 4+5 4+5,总疲劳值为 5 + 5 + 4 + 5 = 19 5+5+4+5=19 5+5+4+5=19

X = 3 X=3 X=3:向住户 3 , 4 , 5 3,4,5 3,4,5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值 3 + 4 + 5 3+4+5 3+4+5,总疲劳值为 5 + 5 + 3 + 4 + 5 = 22 5+5+3+4+5=22 5+5+3+4+5=22

X = 4 X=4 X=4:向住户 2 , 3 , 4 , 5 2,3,4,5 2,3,4,5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值 2 + 3 + 4 + 5 2+3+4+5 2+3+4+5,总疲劳值 5 + 5 + 2 + 3 + 4 + 5 = 24 5+5+2+3+4+5=24 5+5+2+3+4+5=24

X = 5 X=5 X=5:向住户 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值 1 + 2 + 3 + 4 + 5 1+2+3+4+5 1+2+3+4+5,总疲劳值 5 + 5 + 1 + 2 + 3 + 4 + 5 = 25 5+5+1+2+3+4+5=25 5+5+1+2+3+4+5=25

输入输出样例 2 说明

X = 1 X=1 X=1:向住户 4 4 4 推销,往返走路的疲劳值为 4 + 4 4+4 4+4,推销的疲劳值为 4 4 4,总疲劳值 4 + 4 + 4 = 12 4+4+4=12 4+4+4=12

X = 2 X=2 X=2:向住户 1 , 4 1,4 1,4 推销,往返走路的疲劳值为 4 + 4 4+4 4+4,推销的疲劳值为 5 + 4 5+4 5+4,总疲劳值 4 + 4 + 5 + 4 = 17 4+4+5+4=17 4+4+5+4=17

X = 3 X=3 X=3:向住户 1 , 2 , 4 1,2,4 1,2,4 推销,往返走路的疲劳值为 4 + 4 4+4 4+4,推销的疲劳值为 5 + 4 + 4 5+4+4 5+4+4,总疲劳值 4 + 4 + 5 + 4 + 4 = 21 4+4+5+4+4=21 4+4+5+4+4=21

X = 4 X=4 X=4:向住户 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4 推销,往返走路的疲劳值为 4 + 4 4+4 4+4,推销的疲劳值为 5 + 4 + 3 + 4 5+4+3+4 5+4+3+4,总疲劳值 4 + 4 + 5 + 4 + 3 + 4 = 24 4+4+5+4+3+4=24 4+4+5+4+3+4=24。或者向住户 1 , 2 , 4 , 5 1,2,4,5 1,2,4,5推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值为 5 + 4 + 4 + 1 5+4+4+1 5+4+4+1,总疲劳值 5 + 5 + 5 + 4 + 4 + 1 = 24 5+5+5+4+4+1=24 5+5+5+4+4+1=24

X = 5 X=5 X=5:向住户 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5 推销,往返走路的疲劳值为 5 + 5 5+5 5+5,推销的疲劳值为 5 + 4 + 3 + 4 + 1 5+4+3+4+1 5+4+3+4+1,总疲劳值 5 + 5 + 5 + 4 + 3 + 4 + 1 = 27 5+5+5+4+3+4+1=27 5+5+5+4+3+4+1=27

数据范围

对于 20 % 20\% 20% 的数据, 1 ≤ N ≤ 20 1 \le N \le20 1N20
对于 40 % 40\% 40% 的数据, 1 ≤ N ≤ 100 1\le N \le 100 1N100
对于 60 % 60\% 60% 的数据, 1 ≤ N ≤ 1000 1 \le N \le 1000 1N1000
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100000 1 \le N \le 100000 1N100000

代码实现

#include<iostream>
#include<queue>
using namespace std;
#define MAX_N 1000000
struct Data{
	int id,a;
	bool operator<(const Data&c)const{return a<c.a;}
}data; 
int d[MAX_N+5],p[MAX_N+5];
int main()
{
	int n;
	cin>>n;
	priority_queue<Data>s1;
	priority_queue<int>s2;
	int ans=0;
	for(int i=1;i<=n;i++)cin>>d[i];
	for(int i=1;i<=n;i++)
	{
		data.id=i;
		cin>>p[i];
		data.a=d[i]*2+p[i];
		s1.push(data);
	}
	int cur=0;
	int new_pos=0;
	for(int i=1;i<=n;i++)
	{
		int maxL=0,maxR=0;
		if(!s2.empty())maxL=s2.top();
		while(!s1.empty()&&s1.top().id<=cur)s1.pop();
		if(!s1.empty())
		{
			maxR=s1.top().a;
			new_pos=s1.top().id;
		}
		if(maxR-2*d[cur]>maxL)
		{
			for(int i=cur+1;i<new_pos;i++)s2.push(p[i]);
			ans+=(maxR-2*d[cur]);
			cur=new_pos;
			s1.pop();
		}
		else{
			ans+=maxL;
			s2.pop();
		}
		cout<<ans<<'\n';
	}
	return 0;
 } 

[NOIP2012 提高组] 国王游戏

题目描述

恰逢 H 国国庆,国王邀请 n n n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式

第一行包含一个整数 n n n,表示大臣的人数。

第二行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n n n 行,每行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

样例 #1

样例输入 #1

3 
1 1 
2 3 
7 4 
4 6

样例输出 #1

2

提示

【输入输出样例说明】

1 1 1 2 2 2 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

1 1 1 3 3 3 2 2 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

2 2 2 1 1 1 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

按$ 2$、 3 3 3、$1 $这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9

3 3 3 1 1 1、$2 $这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

按$ 3$、 2 2 2 1 1 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9

因此,奖赏最多的大臣最少获得 2 2 2 个金币,答案输出 2 2 2

【数据范围】

对于 20 % 20\% 20% 的数据,有 1 ≤ n ≤ 10 , 0 < a , b < 8 1≤ n≤ 10,0 < a,b < 8 1n10,0<a,b<8

对于 40 % 40\% 40% 的数据,有$ 1≤ n≤20,0 < a,b < 8$;

对于 60 % 60\% 60% 的数据,有 1 ≤ n ≤ 100 1≤ n≤100 1n100

对于 60 % 60\% 60% 的数据,保证答案不超过 1 0 9 10^9 109

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 , 000 , 0 < a , b < 10000 1 ≤ n ≤1,000,0 < a,b < 10000 1n1,000,0<a,b<10000

NOIP 2012 提高组 第一天 第二题

代码实现

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX_N 1000
class BigInt:public vector<int>
{
	public:
		BigInt(){push_back(0);}
		BigInt(int x){
			push_back(x);
			proccess_digit();
		}
		BigInt&operator*=(int x)
		{
			for(int i=0;i<size();i++)
			at(i)*=x;
			proccess_digit();
			return *this;
		}
		BigInt operator/(int x)
		{
			BigInt ret(*this);
			int now=0;
			for(int i=size()-1;i>=0;i--)
			{
				now=now*10+at(i);
				ret[i]=now/x;
				now%=x;
			}
			return ret;
		}
		bool operator>(const BigInt&a)
		{
			if(size()>a.size())return true;
			else if(size()<a.size())return false;
			else{
				for(int i=size()-1;i>=0;i--)
				{
					if(at(i)>a[i])return true;
					else if(at(i)<a[i])return false;
				}
			}
			return false;
		}
		void proccess_digit()
		{
			for(int i=0;i<size();i++)
			{
				if(at(i)<10)continue;
				if(i==size()-1)push_back(0);
				at(i+1)+=at(i)/10;
				at(i)%=10;
			}
			return ;
		} 
};
ostream&operator<<(ostream&out,BigInt&a)
{
	int flag=1;
	for(int i=a.size()-1;i>=0;i--)
	{
		if(flag&&!a[i])continue;
		flag=0;
		out<<a[i];
	}
	if(flag)out<<0;
	return out;
}
int l[MAX_N+5],r[MAX_N+5],ind[MAX_N+5];
bool cmp(int a,int b)
{
	return l[a]*r[a]<l[b]*r[b];
}
int main()
{
	int n;
	cin>>n;
	cin>>l[0]>>r[0];
	for(int i=1;i<=n;i++)
	{
		cin>>l[i]>>r[i];
		ind[i]=i;
	}
	sort(ind+1,ind+1+n,cmp);
	BigInt ans(l[0]/r[ind[1]]),ll(l[0]);
	for(int i=2;i<=n;i++)
	{
		ll*=l[ind[i-1]];
		if(ll/r[ind[i]]>ans)ans=ll/r[ind[i]];
	}
	cout<<ans;
	return 0;
}

皇后游戏

题目背景

还记得 NOIP 2012 提高组 Day1 的国王游戏吗?时光飞逝,光阴荏苒,两年过去了。国王游戏早已过时,如今已被皇后游戏取代,请你来解决类似于国王游戏的另一个问题。

题目描述

皇后有 n n n 位大臣,每位大臣的左右手上面分别写上了一个正整数。恰逢国庆节来临,皇后决定为 n n n 位大臣颁发奖金,其中第 i i i 位大臣所获得的奖金数目为第 i − 1 i - 1 i1 位大臣所获得奖金数目与前 i i i 位大臣左手上的数的和的较大值再加上第 i i i 位大臣右手上的数。

形式化地讲:我们设第 i i i 位大臣左手上的正整数为 a i a_i ai,右手上的正整数为 b i b_i bi,则第 i i i 位大臣获得的奖金数目为 c i c_i ci 可以表达为:

c i = { a 1 + b 1 , i = 1 max ⁡ { c i − 1 , ∑ j = 1 i a j } + b i , 2 ≤ i ≤ n c_{i} = \begin{cases} a_{1}+b_{1} & ,i=1 \\ \displaystyle \max \left \{ c_{i-1},\sum_{j=1}^{i}a_{j} \right \} +b_{i} & ,2\leq i \leq n \end{cases} % ![](https://cdn.luogu.com.cn/upload/pic/1257.png) ci= a1+b1max{ci1,j=1iaj}+bi,i=1,2in

当然,吝啬的皇后并不希望太多的奖金被发给大臣,所以她想请你来重新安排一下队伍的顺序,使得获得奖金最多的大臣,所获奖金数目尽可能的少。

注意:重新安排队伍并不意味着一定要打乱顺序,我们允许不改变任何一位大臣的位置。

输入格式

第一行包含一个正整数 T T T,表示测试数据的组数。

接下来 T T T 个部分,每个部分的第一行包含一个正整数 n n n,表示大臣的数目。

每个部分接下来 n n n 行中,每行两个正整数,分别为 a i a_i ai b i b_i bi,含义如上文所述。

输出格式

T T T 行,每行包含一个整数,表示获得奖金最多的大臣所获得的奖金数目。

样例 #1

样例输入 #1

1
3
4 1
2 2
1 2

样例输出 #1

8

样例 #2

样例输入 #2

2
5
85 100
95 99
76 87
60 97
79 85
12
9 68
18 45
52 61
39 83
63 67
45 99
52 54
82 100
23 54
99 94
63 100
52 68

样例输出 #2

528
902

提示

按照 1 , 2 , 3 1,2,3 1,2,3 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 10 10 10

按照 1 , 3 , 2 1,3,2 1,3,2 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9 9 9

按照 2 , 1 , 3 2,1,3 2,1,3 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9 9 9

按照 2 , 3 , 1 2,3,1 2,3,1 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 8 8 8

按照 3 , 1 , 2 3,1,2 3,1,2 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9 9 9

按照 3 , 2 , 1 3,2,1 3,2,1 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 8 8 8

当按照 3 , 2 , 1 3,2,1 3,2,1 这样排列队伍时,三位大臣左右手的数分别为:

( 1 , 2 ) , ( 2 , 2 ) , ( 4 , 1 ) (1,2),(2,2),(4,1) (1,2),(2,2),(4,1)

  • 1 1 1 位大臣获得的奖金为 1 + 2 = 3 1+2=3 1+2=3
  • 2 2 2 位大臣获得的奖金为 max ⁡ 3 , 3 + 2 = 5 \max{3,3}+2=5 max3,3+2=5
  • 3 3 3 为大臣获得的奖金为 max ⁡ 5 , 7 + 1 = 8 \max{5,7}+1=8 max5,7+1=8

对于全部测试数据满足: T ≤ 10 T\le10 T10 1 ≤ n ≤ 2 × 1 0 4 1\le n\le 2\times 10^4 1n2×104 1 ≤ a i , b i ≤ 1 0 9 1\le a_i,b_i\le 10^9 1ai,bi109

代码实现

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 20000
struct Data{
	int l,r,d;
}chen[MAX_N+5];
bool cmp(Data&a,Data&b)
{
	if(a.d!=b.d)return a.d<b.d;
	else{
		if(a.d==-1)return a.l<b.l;
		else return a.r>b.r;
	}
}
void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>chen[i].l>>chen[i].r;
		if(chen[i].l>chen[i].r)chen[i].d=1;
		else if(chen[i].l==chen[i].r)chen[i].d=0;
		else chen[i].d=-1;
	}
	sort(chen+1,chen+1+n,cmp);
	long long ans=chen[1].l+chen[1].r,ll=chen[1].l;
	for(int i=2;i<=n;i++)
	{
		ll+=chen[i].l;
		ans=max(ans,ll)+chen[i].r;
	}
	cout<<ans<<endl;
	return ;
}
int main()
{
	int T;
	cin>>T;
	while(T--)solve();
	return 0;
 } 
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值