题目简化:给你一个大小为n的原数组a和修改后的数组b。然后会给你m个数,你必须用这m个数按顺序进行操作,操作就是可以把原数组a中的任何一个数变成操作用的数。问你一顿操作下来,原数组a是否可以变成修改后的数组b?
题解:首先我们注意到,想要让原数组a尽量靠近修改后的数组b,就要在两个数组不同的数字之间做文章,而相同的数字我们就不需要管它们了,因此在录入修改后的数组b时,可以与原数组a的同下标数作对比,如果不同,就创建一个map容器,作为桶(哈希表)来收录修改后的数的所需数量。比如原数组a第一个数是2,修改后的数组b第一个数是3,它们不同,这个时候就说明我们需要一个3来修改数组a来接近数组b的样子,因此让3的桶自增,表示我们需要3的数量增加1。
此时我们已经得到了我们将数组a修改为数组b所需要的数和它们对应的所需数量,可以开始着手在m次操作中寻找我们需要的数字。但我们会发现m次操作中除了找所需的数外,还有很多不需要的数字,这些数字我们应该怎么处理?不难看出,操作之间是可以覆盖的,例如3次操作1,2,3,我先把一个数变成1,再变成2,再变成3,最终结果就是这个数变成了3,前面1和2的操作的影响就消失了。也就是说,后面的数可以覆盖前面的数,只要我们最后的数是我们需要的,我们就可以保证前面所有不需要的数字所造成的影响被抵消。
换言之,我们需要最后一个数字属于b,这样就可以保证这个数可以抵消前面所有的不相关数(或者多余数)。因此为了保障这一点,我们只需要回到前面输入b数组的时候,多开一个针对数组b所有元素的桶,记录b所有的元素即可。随后在第m次操作中,我们就看第m次操作的数是否属于数组b,如果属于,正常操作,不属于则说明至少有一个不需要的数字(即第m个数)无法被覆盖,输出"NO"后直接返回。
如此一来,我们便只需要关注那些我们需要的数字即可。在m次操作中,我们看我们是否需要这个数,如果需要,就让这个存储所需元素的桶中的该数字的计数减一,视为我们从这次操作中使用这个数字做了一次有效的操作。在进行完所有的操作之后,我们再遍历我们用于存储所需元素的桶,如果桶中还有数的计数不为0,说明m次操作没办法满足我们的需求,输出NO。否则就说明可以满足需求,输出YES。
AC代码:
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <bitset>
#include <ctime>
using namespace std;
using ll = long long;
ll INF = 4e18;
const int N = 3e5 + 10;
ll a[N], p[N], b[N], c0[N], c1[N], d[N], c[N];
pair<ll, ll> dp[N];
ll mod = 1e9 + 7;
bool vis[N];
map<ll, ll> cnt;
map<ll, ll> cnt2;
bool myCompare(int v1, int v2)
{
return v1 > v2;
}
queue<ll> q;
void solve()
{
cnt.clear();
cnt2.clear();
int n; cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i <= n; i++)
{
cin >> b[i];
cnt2[b[i]]++;
if (a[i] != b[i])cnt[b[i]]++;
}
int m; cin >> m;
for (int i = 1; i <= m; i++)
{
ll temp; cin >> temp;
if (i == m)
{
if (!cnt2[temp])
{
cout << "NO\n";
return;
}
}
if (cnt[temp])
{
cnt[temp]--;
//q.push(temp);
}
}
for (auto& x : cnt)
{
if (x.second)
{
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
int main()
{
ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
int _ = 1; cin >> _;
while (_--)
solve();
return 0;
}