Codeforces Round 961 (Div. 2)

前言

        仿佛这几天都没有在赛前放空大脑,都是瞅着有比赛就直接报名去打了。

        Standings:2520

        题目链接:Dashboard - Codeforces Round 961 (Div. 2) - Codeforces

A. Diagonals

        题意:

        给一个 n * n 的棋盘,你需要把若干个棋子放在棋盘的格子里,每个格子里最多只能放 1 个棋子。假设某个格子在第 i 行第 j 列,定义对角线为所有 (i + j)相等的格子的集合,问最少使用多少条对角线可以把所有棋子都装进去。

        思路:

        简单贪心,把对角线按其格子数从大到小排个序,依次插入棋子即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int T,n,k,m,a[10005],b[100005],cnt;

int cmp(int x,int y) { return x > y ; }

int max(int x,int y) { return x > y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&k),m = n * n,cnt = 0;
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= n;++ j) a[(i - 1) * n + j] = i + j;
		sort(a + 1,a + m + 1),a[m + 1] = -1;
		int now = 1;
		for (int i = 2;i <= m + 1;++ i)
			if(a[i] != a[i - 1] && i) b[++ cnt] = now,now = 1;
			else ++ now;
		sort(b + 1,b + cnt + 1,cmp);
		now = 1;
		while (k)
		{
			k = max(0,k - b[now]);
			++ now;
		}
		printf("%d\n",now - 1);
	}
	return 0;
}

B1. Bouquet (Easy Version)

        题意:

        小女孩要在花店买一束花,花店有 n 朵花,每朵花有若干片花瓣,一片花瓣要花一块硬币。女孩希望买的所有花中,任意两朵之间的花瓣差不超过 1 。她有 m 块硬币,问最多可以买到多少片花瓣。

        思路:

        题目的限制 “ 任意两朵之间的花瓣差不超过 1 ” 其实简化了难度,这样我们要么就是只买花瓣一样的花,要么就是买花瓣数目相差 1 的花,按花朵的花瓣数排个序直接做即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define N 200005

int T,n,a[N],b[N],c[N],cnt;
long long m,ans;

int min(int x,int y) { return x < y ? x : y ; }

long long max(long long x,long long y) { return x > y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%lld",&n,&m),cnt = 0,ans = 0ll;
		for (int i = 1;i <= n;++ i) scanf("%d",&a[i]);
		sort(a + 1,a + n + 1),a[n + 1] = -1;
		int now = 1;
		for (int i = 2;i <= n + 1;++ i)
			if(a[i] != a[i - 1]) b[++ cnt] = now,c[cnt] = a[i - 1],now = 1;
			else ++ now;
		now = 1,c[cnt + 1] = -1;
		while (now <= cnt)
		{
			long long tmp;
			if(c[now + 1] - c[now] > 1 || now == cnt) tmp = 1ll * min(m / c[now],b[now]) * c[now];
			else
			{
				for (int i = 0;i <= b[now];++ i)
				{
					if(1ll * i * c[now] > m) break;
					tmp = 1ll * i * c[now];
					tmp += 1ll * min((m - tmp) / c[now + 1],b[now + 1]) * c[now + 1];
					ans = max(ans,tmp);
				}
			}
			ans = max(ans,tmp);
			++ now;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

B2. Bouquet (Hard Version)

        题意:

        其他背景都相同,只有给出花朵的方式不同,Easy Version 是一个一个花朵列出来,Hard Version 是直接给出不同数目的花瓣对应的花朵数目,1 <= n <= 2 * 10^5 。

        思路:

        思路和 Easy Version 一致,现在考虑如何快速计算选两种花朵的答案。

        乍一看是背包问题,但是不是常规的背包,因为相当于只有两个物品,且两个物品的价值刚好相差 1 ,这说明存在简单快速的方法。假设两种花的花瓣数分别为 x 和 x + 1,我们贪心地想,先尽量填满 x ,再填 x + 1 。假设已经塞不下 x 了,说明也不可能塞得下 x + 1 了;若尽可能塞完后背包还有小于 x + 1 的空间,且还有没塞入的 x + 1 ,我们就考虑用尽可能多的 x + 1 替代 x ,这样每替换一次就多利用了 1 的空间。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define N 200005

int T,n;
long long m,ans;

struct Node
{
	long long b,c;
}a[N];

long long min(long long x,long long y) { return x < y ? x : y ; }

long long max(long long x,long long y) { return x > y ? x : y ; }

int cmp(Node x,Node y) { return x.c < y.c ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%lld",&n,&m),ans = 0ll;
		for (int i = 1;i <= n;++ i) scanf("%lld",&a[i].c);
		for (int i = 1;i <= n;++ i) scanf("%lld",&a[i].b);
		sort(a + 1,a + n + 1,cmp),a[n + 1].c = -1ll;
		int now = 1;
		while (now <= n)
		{
			long long tmp;
			if(a[now + 1].c - a[now].c > 1 || now == n) tmp = 1ll * min(m / a[now].c,a[now].b) * a[now].c;
			else
			{
				long long numx = min(m / a[now].c,a[now].b);
				tmp = 1ll * numx * a[now].c;
				long long numy = min((m - tmp) / a[now + 1].c,a[now + 1].b);
				tmp += 1ll * numy * a[now + 1].c;
				if(tmp < m && numy < a[now + 1].b) tmp += 1ll * min(numx,min(m - tmp,a[now + 1].b - numy));
			}
			ans = max(ans,tmp);
			++ now;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

C. Squaring

        题意:

        给一个序列 a ,每次操作可以让某个数变成它的平方,问至少用多少次操作能使序列非降。

        思路:

        朴素的想法是从左到右遇到一个不合法的就让它平方直至合法,但这样可能会超时且超过 long long 甚至 int64 的范围。自然而然想到可以取对数,在对数层面计算就不会超范围了。

        设前一个数为 x ,当前这个数为 y ,若 x > y 我们就需要进行操作:

        x <= y^{2^k}

        \log_2 x <= 2^k \log_2 y

        \log_2(\log_2 x) <= k + \log_2(\log_2 y)

        k >= \log_2(\log_2 x) - \log_2(\log_2 y)

        因此我们对每个数取两次 log 再操作即可。

        Tips:

        其实这道题还有整数的做法,我们不需要真正地将某个数平方那么多次,只需要记录每个数平方了多少次(记作 p)即可。我们需要在原始数组上预处理出每个数与他前面那个数在平方次数上相差多少次(记作 x),若前面那个数需要平方两次或以上才能超过当前这个数,那么 x 就是负数;若前面那个大于当前这个数,则 x 是正数;否则 x 是 0 。那么当前这个数的 p 就是 x 加上前面那个数的 p 。

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

#define N 200005

int T,n,p[N];
double a[N],b[N];
long long ans;

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d",&n);
		for (int i = 1;i <= n;++ i) scanf("%lf",&a[i]),b[i] = log(log(a[i])),p[i] = 0;
		ans = 0ll;
		int flag = 1;
		for (int i = 2;i <= n;++ i)
		{
			double x = b[i - 1];
			double y = b[i];
			if(y < x)
			{
				if(a[i] == 1.00)
				{
					flag = 0;
					break;
				}
				p[i] = floor((x - y - 1e-9) / log(2)) + 1;
				b[i] += log(2) * p[i];
			}
		}
		if(!flag)
		{
			printf("-1\n");
			continue;
		}
		for (int i = 1;i <= n;++ i) ans += 1ll * p[i];
		printf("%lld\n",ans);
	}
	return 0;
}

剩下的题以后再补,挖个坑 。

总结

        这场比赛 C 其实已经做出来了,但是比赛玄学时间总是让我慢了几秒钟,总的来说还是时间的把控要再磨炼,前面简单题和思维题的解题速度要提升。

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的购买多种花束的代码示例: ```python # 花束的类定义 class Bouquet: def __init__(self, name, price): self.name = name self.price = price # 主程序 def main(): # 定义几个花束 bouquet1 = Bouquet("玫瑰花束", 99.9) bouquet2 = Bouquet("康乃馨花束", 89.9) bouquet3 = Bouquet("百合花束", 79.9) # 输出花束信息 print("欢迎光临我们的花店!") print("我们有以下花束可供选择:") print("1. " + bouquet1.name + ",价格:" + str(bouquet1.price) + "元") print("2. " + bouquet2.name + ",价格:" + str(bouquet2.price) + "元") print("3. " + bouquet3.name + ",价格:" + str(bouquet3.price) + "元") # 让用户选择要购买的花束和数量 choice = input("请输入要购买的花束编号(1-" + str(3) + "):") quantity = int(input("请输入要购买的数量:")) # 根据用户的选择计算总价 if choice == "1": total_price = bouquet1.price * quantity elif choice == "2": total_price = bouquet2.price * quantity elif choice == "3": total_price = bouquet3.price * quantity else: print("输入无效!") return # 输出总价和谢谢信息 print("您选择了购买 " + str(quantity) + " 个 " + eval("bouquet" + choice).name) print("总价为:" + str(total_price) + "元") print("谢谢惠顾!") # 调用主程序 main() ``` 在上面的代码中,我们首先定义了一个 `Bouquet` 类来表示花束。然后在主程序中,我们创建了几个 `Bouquet` 实例来表示三种不同的花束,并将它们的信息打印出来供用户选择。 用户输入要购买的花束编号和数量后,我们根据用户的选择计算总价,并输出购买信息和总价。如果用户输入了无效的选择,则程序会提示输入无效并退出。 这只是一个简单的示例,实际情况可能更复杂,需要根据具体需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值