C. Fence Painting(ranting 1600)超详细题解

C. Fence Painting(ranting 1600)超详细题解



前言

本系列的意义在于两点,一则是作为本人(一个编程初学者)的学习笔记记录,二则希望能对后来者提供一些帮助,因为本人也为新手,难免有些错误或讲述不清之处,恳请大家指出或提出建议,本人也会虚心修改。

本系列的目标是帮助大家解决一些codeforces上,ranting1600+(或者之后会改为1300+,看博主水平吧)的题目


一、题目及翻译

1. 原题(贴图)

Alt
【戳我跳转到题目】

2. 翻译
  1. 机翻版
    Alt
  2. 省流版
    给定的n和数列a和数列b,再给定m个元素(每个元素只能用一次),让我们用且必须用m次操作,将a通过给定元素替换成b

二、解析及AC代码

1.解析

我们先讨论一下无解的情况:

  1. 如果给的颜色全是b中不存在的。为什么呢 ? 如果给的颜色全是b中不存在的,那么无论,怎么涂,都必定会使a与b至少有一个元素不同
  2. 如果在 a i a_i ai ≠ \neq = b i b_i bi时,c中不存在 b i b_i bi为什么呢? 如果在 a i a_i ai ≠ \neq = b i b_i bi时,c中不存在 b i b_i bi,那么无论,怎么涂,都必定会使 a i a_i ai b i b_i bi不同

如果题目不是以上两种情况则有解,那么怎么构造出解呢?从贪心的角度思考,当存在 a i a_i ai ≠ \neq = b i b_i bi时,我们刷上 b i b_i bi,否则我们将c中所有元素刷到最后一个 a i a_i ai= b i b_i bi= c j c_j cj的地方去(可以理解为找到最后刷的地方,然后将其他元素当做不存在元素对待),而对于不存在的元素,我们把它刷到最后一个刷的地方去

那么,此时同学们就可以自己去尝试一下了,如果还是不太理解,可以参考下博主下面的AC代码

2.AC代码
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>
#include<queue>

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

const int N = 1e5 + 10, MAXN = 0x3f3f3f3f;

int n, m;
int a[N], b[N], c[N], res[N];
vector<int>g[N];

int main()
{
  int t;
  cin >> t;
  while (t--)
  {
  	scanf("%d %d", &n, &m);
  	for (int i = 1; i <= n; i++) g[i].clear();
  	for (int i = 1; i <= n; i++)
  		scanf("%d", &a[i]);
  	for (int i = 1; i <= n; i++)
  	{
  		scanf("%d", &b[i]);
  		if (b[i] != a[i])
  			g[b[i]].push_back(i);
  	}
  	for (int i = 1; i <= m; i++)
  	{
  		scanf("%d", &c[i]);
  	}
  	int last = -1;//last纪录最后一个被粉刷的地方
  	if (g[c[m]].size() > 0)//存在a[i]!=b[i]
  	{
  		last = g[c[m]].back();
  		g[c[m]].pop_back();
  	}
  	else
  	{
  		for (int i = 1; i <= n; i++)
  		{
  			if (b[i] == c[m])
  			{
  				last = i;
  				break;
  			}
  		}
  	}
  	if (last == -1)//给的颜色全是b中不存在的
  	{
  		puts("NO");
  		goto A;
  	}
  	res[m] = last;
  	for (int i = 1; i < m; i++)
  	{
  		if (g[c[i]].size() == 0)
  		{
  			res[i] = last;//不存在的元素,把它刷到最后一个刷的地方去
  		}
  		else
  		{
  			res[i] = g[c[i]].back();//注意是c[i],实际上是在找a[i]!=b[i]时,是否存在c[i]==b[i]
  			g[c[i]].pop_back();
  		}
  	}
  	for (int i = 1; i <= n; i++)
  	{
  		if (g[i].size() > 0)//a[i] != b[i]时,不存在c[i] == b[i]
  		{
  			puts("NO");
  			goto A;
  		}
  	}
  	puts("YES");
  	for (int i = 1; i <= m; i++)
  	{
  		printf("%d ", res[i]);
  	}
  	cout << endl;
  A:
  	continue;
  }
  return 0;
}

如果觉得有用还请点个赞吧,拜托拜托

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值