ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 I

这题应该说没什么算法,最多就是一些技巧在里面;

关键是题意真是复杂,给的变量就很多。然后根据已知的变量,我们可以求出每个导弹第一次攻击到A的时间st和最后一次攻击到的时候ed(假设A会弹回去的最后一次);防御时间必须 包含[st,ed],这个防御才能成功 

问题就转化为 求一个固定长度的区间,使得这个区间覆盖的可防御伤害最大。

怎么求这个区间的位置呢?

只要把每个导弹的st和ed两个点放到一个数组里,然后把所有点排序;然后把防御区间从左往右移,碰到一个左端点,当前覆盖的防御值减掉它会造成的伤害,碰到一个右端点加上去,就可以在n 时间内求出最大可防御伤害,最后的答案就是 A总的可能能受到的伤害 - 最大可防御的伤害


【代码】

#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<stdlib.h>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
int LTA, LTB;
int XB;
int N, M;
int ta[MAXN], tb[MAXN];
int fa[MAXN], fb[MAXN];
int da[MAXN], db[MAXN];
struct Node
{
	int d;
	int t;
	int len;
	int flag;
}node[2 * MAXN];
int nodeLen = 0;
void AddNode(int t, int len, int flag, int d)
{
	node[nodeLen].t = t;
	node[nodeLen].len = len;
	node[nodeLen].flag = flag;
	node[nodeLen].d = d;
	nodeLen++;
}
bool comp(Node a, Node b)
{
	return a.t < b.t;
}

int main(void) {
#ifndef ONLINE_JUDGE
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#endif
	int i;
	int T;
	int stB, edB;
	int st, ed, cnt;
	while (scanf("%d%d", &LTA, &LTB) != EOF)
	{
		int total = 0;
		scanf("%d", &XB);
		stB = XB;
		edB = XB + LTB;
		scanf("%d%d", &N, &M);
		for (i = 0; i < N; i++)
		{
			scanf("%d%d%d", &ta[i], &fa[i], &da[i]);
			total += da[i];
		}
		for (i = 0; i < M; i++)
		{
			scanf("%d%d%d", &tb[i], &fb[i], &db[i]);
			total += db[i];
		}
		nodeLen = 0;
		for (i = 0; i < N; i++)
		{
			if (ta[i] + fa[i] >= stB && ta[i] + fa[i] <= edB)
			{
				st = ta[i] + fa[i] * 2;
				cnt = (edB - ta[i] - fa[i]) / fa[i];
				if (cnt % 2 == 0)
				{
					ed = ta[i] + fa[i] + fa[i] * (cnt + 1);
				}
				else
				{
					ed = ta[i] + fa[i] + fa[i] * cnt;
				}
				AddNode(st, ed -st, 0, da[i]);
				AddNode(ed, ed -st, 1, da[i]);
			}
			else
			{
				total -= da[i];
			}
		}
		for (i = 0; i < M; i++)
		{
			if (tb[i] + fb[i] * 2 >= stB && tb[i] + fb[i] * 2 <= edB)
			{
				st = tb[i] + fb[i];
				cnt = (edB - tb[i] - 2 * fb[i]) / fb[i];
				if (cnt % 2 == 0)
				{
					ed = tb[i] + 2 * fb[i] + fb[i] * (cnt + 1);
				}
				else
				{
					ed = tb[i] + 2 * fb[i] + fb[i] * cnt;
				}
				AddNode(st, ed - st, 0, db[i]);
				AddNode(ed, ed - st, 1, db[i]);
			}
			else
			{
				st = tb[i] + fb[i];
				ed = st;
				AddNode(st, ed - st, 0, db[i]);
				AddNode(ed, ed - st, 1, db[i]);
			}
		}
		sort(node, node + nodeLen, comp);
		int res = 0;
		int maxRes = 0;
		st = 0;
		ed = 0;
		while (st < nodeLen)
		{
			int t = node[st].t;
			while (ed < nodeLen && node[ed].t <= t + LTA)
			{
				if (node[ed].flag == 1 && node[ed].len <= LTA)
				{
					res += node[ed].d;
				}
				ed++;
			}
			if (res > maxRes)
			{
				maxRes = res;
			}
			while (st < nodeLen && node[st].t == t)
			{
				if (node[st].flag == 0 && node[st].len <= LTA)
				{
					res -= node[st].d;
				}
				st++;
			}
		}
		printf("%d\n", total - maxRes);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值