codeforces思维题题解(950 div3 C)

原题:Problem - C - Codeforces

题目简化:给你一个大小为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;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值