每日一题~1969积木大赛,国王的游戏(贪心+高精度),奶牛玩杂技

洛谷
题意:
n
a1 a2 a3 …an
每次可以选择连续的一段区间,区间内的数都加1,询问至少多少次,能够将n 个0,转化成 给出的序列。
做题的时候没想到这个贪心。只想到了分治的思路。
思路:
将区间化划分成 若干不降区间(贪心的操作,确保每个不降区间尽可能的大)
2 3 4 /1 2
我们可以发现,
如果右边比左边低,那么在操作左边的时候,右边的已经满足了
如果右边比左边高,那么必须 额外的操作上 两者的差值。

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

int main()
{
	std::cin.tie(nullptr)->sync_with_stdio(false);
	int n;	cin>>n;
	
	vector<int>a(n);
	for(int i=0;i<n;i++)
	cin>>a[i];
	
	 int ans=a[0];
	 for (int i=1;i<n;i++)
	 {
	 	ans+=max(0,a[i]-a[i-1]);
	 }
	 cout<<ans<<"\n";
	 
	return 0;
 } 

国王游戏
感性的思考一下:
要使最大值最小,(咋一听,有点二分的感觉,但实际上是贪心)要使得最大值最小,也就是削弱每位大臣的奖励。
因为左手上的数都是大于等于1的,所以 越到 后面,积越大。同时 越排在前面,左手数值产生的影响就越大。所以 我们可以粗略的感知到,左手数值小的在前面。
我们现在看右手数值,因为左右的累积是越来越大的,所以应该将右手数值大的放后面,换言之,右手数值小的在前面。
综上,看完题目,我们可以隐隐感觉出来,左右手小的排在前面。那么严谨点的排序依据什么(和?乘积?)
我们来研究 相邻 的两个数
在这里插入图片描述
在这里插入图片描述

综上可以看出来,我们应该按照 左右手乘积的方式排序。
之后 再配合 一点点 的高精度,既可以 愉快的把这道题 ac过去了。

#include <bits/stdc++.h>
using namespace std;
// 主要的思路:
//根据我们推导出来的,排序之后
//计算每一个大臣的奖励,找到其中的最大值
//输出答案 
//其中 包含 高精度*低精度  高精度/低精度 
// 乘积最大是  10000^1000  
// 也就是 10^4000 也就是 4000位

struct node
{
	int a,b;
	bool operator <(node &t){
		return a*b<t.a*t.b;
	}
 }p[1005] ;//最多有 1e3个 
 int m[4005],a[4005],t[4005];
 //m 存储乘积,a存答案 
 int lm,la,lt;
 void div(int *m,int b,int *t)
 {
 	for (int i=1;i<=lt;i++)t[i]=0;
 	int r=0;
 	for (int i=lm;i>=1;i--){
 		r=r*10+m[i];
 		t[i]=r/b;
 		r%=b;
	 }
	 lt=lm;
	 while(t[lt]==0&&lt>1)lt--;
 }
 void mul(int *m,int b,int *t)
 {
 	for (int i=1;i<=lt;i++)t[i]=0;
 	for (int i=1;i<=lm;i++)t[i]+=m[i]*b;
 	lm+=4;
 	for (int i=1;i<lm;i++)
 	{t[i+1]+=t[i]/10;
 	t[i]%=10;
 	
	 }
	 while(t[lm]==0&&lm>1)lm--;
	 for (int i=1;i<=lm;i++)
	 m[i]=t[i];
 }
 bool cmp(int *a,int *t)
 {
 	if (la!=lt) return la<lt;
 	for(int i=lt;i;i--)
 	{
 		if (a[i]!=t[i])
 		return a[i]<t[i];
	 }
	 return false;//相等的情况 
 }
 void upd(int *a,int *t)
 {
 	if (cmp(a,t)){
 		//如果 a<t,更新答案
		 for (int i=lt;i;i--)a[i]=t[i];
		 la=lt; 
	 }
  } 
int main()
{
	int n;cin>>n;
	for (int i=0;i<=n;i++){
		cin>>p[i].a>>p[i].b;
	}
	sort(p+1,p+n+1);
	m[++lm]=p[0].a;//从1 开始存储 
	for (int i=1;i<=n;i++){
		div(m,p[i].b,t);//将结果存储在t数组中 
		upd(a,t);
		mul(m,p[i].a,t);
	} 
	for (int i=la;i;i--)cout<<a[i];
	
	return 0;
}

添加链接描述
这道题:
直觉上 应该把 重的力量大的放在下面。
我们可以猜测 按照 重量+力量 来排序。
贪心的证明:每一步都是最优的,那么全局最优
在这里插入图片描述

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

bool cmp(pair<int,int>&a,pair<int,int>&b)
{
	return a.first+a.second<b.first+b.second;
}
int main()
{
	std::cin.tie(nullptr)->sync_with_stdio(false);
	int n;cin>>n;
	vector<pair<int,int>>ve(n);
	for (int i=0;i<n;i++)
	{
		cin>>ve[i].first>>ve[i].second;
	}
	sort(ve.begin(),ve.end(),cmp);

	int ans=-2e9;int sum=0;
	for (int i=0;i<n;i++)
	{
		
		ans=max(ans,sum-ve[i].second);
		sum+=ve[i].first;
	}
	cout<<ans<<"\n";
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值