2019 南昌 ICPC G winner 计蒜客重现赛

本文介绍了一个竞技比赛中选手可能生存到最后的策略。通过分析比赛模式和个人能力值,文章提出了一种递推方法来确定哪些参赛者有可能成为最终胜者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

G winner

题意

n n n个人参加竞技比赛
比赛由三种模式,每种模式, n n n个人有不同得能力值
举行 n − 1 n-1 n1场比赛,每场比赛选择两个人决斗,能力值低的人淘汰
q q q个询问,返回该角色是否有可能生存到最后

分析

容易想到任意场的最强者一定是可能生存到最后的

若场数足够,能在其他两场打败该场最强者的人,可能生存到最后(即最强者打败除该人以外所有人,该者最后打败最强者)
1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5
1 , 2 , 3 , 5 , 4 1,2,3,5,4 1,2,3,5,4
由5打败1,2,3,最后4打败5

若场数足够,能打败(能打败最强者的人),也有可能生存到最后
1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5
1 , 2 , 3 , 5 , 4 1,2,3,5,4 1,2,3,5,4
1 , 2 , 4 , 5 , 3 1,2,4,5,3 1,2,4,5,3
由5打败1,2,再由4打败5,最后由3打败4

依次类推,逐步递推,寻找能够打败前者的人。
先对三种模式能力离散化,
再预处理后缀和,便于下面递推

代码

后缀和处理

先预处理出第i场排名第i的人,另外两场的排名
再处理第i-n场中,在另外两场的最低排名

//预处理出第i场排名第i的人,另外两场的排名
for (int i = 1; i <= n; i++) {
		num1[a[1][i]].second = a[2][i]; num1[a[1][i]].third = a[3][i];
		num2[a[2][i]].first = a[1][i]; num2[a[2][i]].third = a[3][i];
		num3[a[3][i]].first = a[1][i]; num3[a[3][i]].second = a[2][i];
	}
//处理第i-n场中,在另外两场的最低排名
m1[n + 1][2] = m1[n + 1][3] =
m2[n + 1][1] = m2[n + 1][3] =
m3[n + 1][1] = m3[n + 1][2] = inf;
for (int i = n; i >= 1; i--) {
		m1[i][2] = min(m1[i + 1][2], num1[i].second);
		m1[i][3] = min(m1[i + 1][3], num1[i].third);
		m2[i][1] = min(m2[i + 1][1], num2[i].first);
		m2[i][3] = min(m2[i + 1][3], num2[i].third);
		m3[i][1] = min(m3[i + 1][1], num3[i].first);
		m3[i][2] = min(m3[i + 1][2], num3[i].second);
	}

递推

初始在每场排名最低限制为n-1(排名在第i场在 m i n [ i ] min[i] min[i]以上是可能赢得人)
每次递推推出能打败每场最低限制的人,在其他两场的最低排名

int min1 = n - 1, min2 = n - 1, min3 = n - 1,
		pre1 = inf, pre2 = inf, pre3 = inf;
for (int i = 1; i < n; i++) {
		pre2 = min(pre2, m1[min1 + 1][2]); pre3 = min(pre3, m1[min1 + 1][3]);
		pre1 = min(pre1, m2[min2 + 1][1]); pre3 = min(pre3, m2[min2 + 1][3]);
		pre1 = min(pre1, m3[min3 + 1][1]); pre2 = min(pre2, m3[min3 + 1][2]);
		min1 = min(min1, pre1);
		min2 = min(min2, pre2);
		min3 = min(min3, pre3);
}

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 100005;
const int inf = 1e9;
struct Node
{
	int first;
	int second;
	int third;
}num1[maxn], num2[maxn], num3[maxn];
int a[4][maxn], m1[maxn][4], m2[maxn][4], m3[maxn][4];
bool vis[maxn];
pii p[maxn];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n, q;
	cin >> n >> q;
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= n; j++)
			cin >> a[i][j];
	for (int i = 1; i <= 3; i++) {
		for (int j = 1; j <= n; j++)
			p[j] = pii(a[i][j], j);
		sort(p + 1, p + 1 + n);
		for (int j = 1; j <= n; j++)
			a[i][p[j].second] = j;
	}
	for (int i = 1; i <= n; i++) {
		num1[a[1][i]].second = a[2][i]; num1[a[1][i]].third = a[3][i];
		num2[a[2][i]].first = a[1][i]; num2[a[2][i]].third = a[3][i];
		num3[a[3][i]].first = a[1][i]; num3[a[3][i]].second = a[2][i];
	}
	m1[n + 1][2] = m1[n + 1][3] =
	m2[n + 1][1] = m2[n + 1][3] =
	m3[n + 1][1] = m3[n + 1][2] = inf;
	for (int i = n; i >= 1; i--) {
		m1[i][2] = min(m1[i + 1][2], num1[i].second);
		m1[i][3] = min(m1[i + 1][3], num1[i].third);
		m2[i][1] = min(m2[i + 1][1], num2[i].first);
		m2[i][3] = min(m2[i + 1][3], num2[i].third);
		m3[i][1] = min(m3[i + 1][1], num3[i].first);
		m3[i][2] = min(m3[i + 1][2], num3[i].second);
	}
	int min1 = n - 1, min2 = n - 1, min3 = n - 1,
		pre1 = inf, pre2 = inf, pre3 = inf;
	for (int i = 1; i < n; i++) {
		pre2 = min(pre2, m1[min1 + 1][2]); pre3 = min(pre3, m1[min1 + 1][3]);
		pre1 = min(pre1, m2[min2 + 1][1]); pre3 = min(pre3, m2[min2 + 1][3]);
		pre1 = min(pre1, m3[min3 + 1][1]); pre2 = min(pre2, m3[min3 + 1][2]);
		min1 = min(min1, pre1);
		min2 = min(min2, pre2);
		min3 = min(min3, pre3);
	}
	for (int i = 1; i <= n; i++) {
		if (a[1][i] > min1)vis[i] = true;
		if (a[2][i] > min2)vis[i] = true;
		if (a[3][i] > min3)vis[i] = true;
	}
	int x;
	while (q--) {
		cin >> x;
		if (vis[x])cout << "YES\n";
		else cout << "NO\n";
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值