2019中国大学生程序设计竞赛-女生专场(重现赛),HDU 6551和HDU 6546

2020/7/10
队友拉的一场训练赛,趁热总结一波,A(HDU6544) B(HDU6545) K(HDU6554)都没啥好说的,属于比较简单的签到题,顺便吐槽一下为什么单行输出末尾要回车以及有的题面不说明多行输入。
G(HDU6550)需要注意精度,PI的小数点需要很多位。
下面就是主要的总结了:

  1. H(HDU6551) Clock:
    在这里插入图片描述
    一道不难但是有坑的枚举模拟题,赛中想到了顺、逆、先顺后逆、先逆后顺的枚举方法,无奈代码写飘了,正确的枚举方式:先将每个时间转化为秒(小时需要对12取模)记为a,分别计算出在顺时针与逆时针的情况下每个时间与当前时间的秒数差值记为b和c,然后按照b的大小从小到大将他们进行排序(c也可以,后续做法对应更改即可),排序之后,枚举出各个时刻作为先顺后逆中顺的终点算出对应情况下的ans(即为x[i].b2+x[i+1].c可以理解为先把当前状态下的秒针移到该时刻下,然后再移回去所以是2b最后再移到排序后的下一个时刻的逆时针秒数差值),再枚举出各个时刻作为先逆后顺中逆的终点算出对应情况下的ans(即为x[i].b*2+x[i-1].c同理可得),如果是端点则不需要再+后面的值,即只顺或只逆的情况。
    代码:
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define pi 3.1415926535898
struct ss
{
	int a, b, c;
}x[89000];
bool cmp(ss a, ss b)
{
	return a.b < b.b;
}
bool lesser(ss a, ss b)
{
	return a.a < b.a || (a.a == b.a && a.b < b.b) || (a.a == b.a && a.b == b.b && a.c <= b.c);
}
int main() {
	int n;
	while (cin >> n)
	{
		ss t;
		cin >> t.a >> t.b >> t.c;
		t.a %= 12;
		int s = t.a * 3600 + t.b * 60 + t.c;
		int i;
		int ans = 25 * 3600;
		for (i = 0; i < n; i++)
		{
			cin >> x[i].a >> x[i].b >> x[i].c;
			x[i].a %= 12;
			x[i].a = x[i].a * 3600 + x[i].b * 60 + x[i].c;
			if (x[i].a > s)
			{
				x[i].b = x[i].a - s;
				x[i].c = s - x[i].a + 12 * 3600;
			}
			else
			{
				x[i].b = x[i].a - s + 12 * 3600;
				x[i].c = s - x[i].a;
			}
			//cout << x[i].a << ' ' << x[i].b << ' ' << x[i].c << endl;
		}
		sort(x, x + n, cmp);
		for (i = 0; i < n; i++)
		{
			if (i != n - 1)
			{
				ans = min(ans, x[i].b * 2 + x[i+1].c);
			}
			else
			{
				ans = min(ans, x[i].b);
			}
		}	
		for (i = 0; i < n; i++)
		{
			if (i != 0)
			{
				ans = min(ans, x[i].c * 2 + x[i-1].b);
			}
			else
			{
				ans = min(ans, x[i].c);
			}
			
		}
		cout << ans*6 << ".00" << endl;
	}
	return 0;
}
  1. C(HDU6545) Function:
    题目较短易理解:
    在这里插入图片描述
    和上面一题的区别是赛中完全没有想法,赛后补题发现并不难,写起来很快。。
    整道题就是让你分配x,使得xi的和为m,要求Fi(xi)和最小,因为x是正整数,所以每个Fi都必须先分配xi=1。这时候还剩下m-n个1没有分配,采用贪心原则。首先需要先知道对于每一次分配的1,产生的增量为Fi(xi+1)-Fi(xi)=2ai*x+ai+bi,所以我们每次都取最小的增量,最后即为最小的增量。具体步骤:创建一个优先队列,按照增量的大小进行排序,先将之前的n个已经分配过的结构体插入到优先队列,然后进行m-n次操作,每次取增量最小的(top()),修改其x++,以及修改其增量为最新增量,然后再push进优先队列。m-n次操作之后,所有的1都分配完成,将队列中的结果进行计算累加即可。
    代码:
#include<math.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define pi 3.1415926535898
struct ss
{
	int a, b, c, x, cd;
	bool operator < (const ss& s) const
	{
		return cd > s.cd;
	}
}x[100005];
priority_queue<ss> s;
int main() {
	int n, m;
	while (cin >> n >> m)
	{
		int i;
		for (i = 0; i < n; i++)
		{
			cin >> x[i].a >> x[i].b >> x[i].c;
			x[i].x = 1;
			x[i].cd = 2 * x[i].a * x[i].x + x[i].b+x[i].a;
			s.push(x[i]);
		}
		m -= n;
		while (m--)
		{
			auto p = s.top();
			s.pop();
			p.x++;
			p.cd = 2 * p.a * p.x + p.b+p.a;
			s.push(p);
		}
		long long ans = 0;
		while (s.size())
		{
			auto p = s.top();
			ans += p.a * p.x * p.x + p.b * p.x + p.c;
			s.pop();
		}
		cout << ans << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值