2023牛客寒假算法基础集训营5题解 4/12

本文介绍了三个算法问题的解决方案,涉及前缀和、二分查找和贪心策略。在小沙的好客问题中,通过排序、前缀和和二分查找确定最优解;小沙的博弈问题中,解释了如何通过贪心策略判断游戏结果;小沙的店铺和抱团问题展示了模拟算法在解决商业和数学问题中的应用。
摘要由CSDN通过智能技术生成

< 已写:A 、B 、H 、 K>

更好的观看体验

其他的随后补

A - 小沙の好客

题目链接小沙の好客
算法标签:【前缀和】【二分】
思路:先对商品的价格进行排序,然后进行前缀和操作,最后用二分函数upper_bound()找到第一个大于目标值的位置,遍历得出答案。
upper_bound()和lower_bound()的不同【@brandong】:

lower_bound(begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound(begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

代码
代码链接

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

ll a[N] , s[N];
int n , q;
int k , x;

void solve()
{
    scanf("%d%d",&k,&x);
    
    /*二分找到目标值所在位置,减去数组初始位置,则为目标值下标*/
    int r = upper_bound(a+1,a+n+1,x) - (a+1);
    int l = max(0,r - k + 1);
    
    /*利用前缀和,得出答案*/
    printf("%lld\n",s[r] - s[l - 1]);
}

int main()
{
    scanf("%d%d",&n,&q);
    
    for(int i = 1;i <= n;i ++)
        scanf("%lld",&a[i]);
    
    sort( a+1 , a+1+n );
    
    for(int i = 1;i <= n;i ++)
        s[i] = s[i - 1] + a[i];
    
    while( q-- )
        solve();
    
    return 0;
}

B - 小沙の博弈

题目链接小沙の博弈
算法标签:【贪心】?(bushi)
思路:小沙和小雅两人分别取石子,小沙先取。每个人要使自己的字典序最小的话,每次只取一个,构成字典序:111...

  • 如果石子的个数是偶数的话,每个人取到的石子数相同,平局。
  • 如果石子的个数是奇数的话,小沙比小雅多取一个 (小沙先取!),因此小雅获胜。

代码
代码链接

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    if(n % 2 == 0)
        puts("win-win!");
    else
        puts("Yaya-win!");
    
    return 0;
}

H - 小沙の店铺

题目链接小沙の店铺
算法标签:【模拟】
思路:每次售出时,可以用cnt来记录共售卖的货品数,以便得到上涨后的价格。

  • 注意开long long

代码
代码链接

#include <iostream>

using namespace std;

typedef long long ll;

int main()
{
	ll x , y , k , n , t;
	scanf("%lld %lld %lld %lld %lld",&x,&y,&k,&n,&t);
	// x : 初始价格 
	// y : 每次上涨价格
	// k : 卖出k个物品,涨价
	// n : 共有n个客户
	// t : gmv
	
	ll pri = x; // 目前的价格
	ll sum = 0; // 收入
	ll cnt = 0; // 已售出的货物数量
	
	ll i;
	for(i = n;i >= 1;i --)
	{
		sum += pri*i; // 计算收入
		
		cnt += i;
		pri = x + (cnt/k) * y; // 计算涨价后的价格
		
		if(sum >= t) // 如果达到目标值,直接退出
			break;
	}
	
	if(sum < t) // 如果所有的顾客都已购买后,仍未达到目标值,输出-1
		printf("-1\n");
	else
		printf("%lld\n",n-i+1);
	
	return 0;
}

K - 小沙の抱团 easy

题目链接小沙の店铺
算法标签:【模拟】【贪心】
思路:每次使得淘汰的人数最多,所需要的指令就越少

  • 当场上的人数是偶数时,那么就抱团(人数/2+1),使得淘汰的人数最多
  • 当场上的人数是奇数时,抱团(奇数/2)向上取整 --> (奇数+1)/2,使得淘汰的人数最多

代码
代码链接

#include <iostream>
#include <cmath>

using namespace std;

typedef long long ll;

int main()
{
	ll n;
	scanf("%lld",&n);
	
	ll ans = 0; // 存放指令个数
	
	while(n > 2)
	{
		if( n%2 ) //奇数时
			n = (n+1) / 2;
		else //  偶数时
			n = n / 2 + 1;
		
		ans ++;
	}
	
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值