codeforce 733 D.Secret Santa

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

codeforce 733 D.Secret Santa


题意

有n个人 每个人都有自己想送礼物的人 每人只能收到一个礼物 不能送给自己 每个人都要收到礼物 安排一下 使得满足 送到自己的想要送的人的人数最大化

提示:以下是本篇文章正文内容,下面案例可供参考

1.AC代码

#include <bits/stdc++.h>
#define endl "\n"    
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const  ll mod = 3221225473;
const int maxn = 1e5 + 1;
void solve()
{
    int n,tot=0;
    cin >> n;
    vector<ll> pos(n+1),a(n+1);  // a是记录人们想要送的  pos是记录送此位置的谁
    vector<bool>used(n + 1), vis(n + 1); // used 记录有没有被送过 vis 记录有没有送过人
    set<ll>s;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        s.insert(i);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!used[a[i]])
        {
            used[a[i]] = vis[i] = 1;
            tot++;
            s.erase(a[i]);
            pos[a[i]] = i;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            auto it = s.begin();
            if (*it != i)
            {
                a[i] = *it;
                used[a[i]] = 1;
                vis[i] = 1;
                pos[a[i]] = i;
            }
            else
            {
                ll id = pos[a[i]];
                a[i] = *it;
                swap(a[i], a[id]);
                pos[a[i]] = i, pos[a[id]] = id;
            }
            s.erase(it);
        }
    }
    cout << tot << endl;
    for (int i = 1; i <= n; i++)
        cout << a[i] << " ";
    cout << endl;
}
int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

做法总结

能够做到的使期望值达最大的数目刚好等于a中出现不重复数字的数量

用s(set)来记录谁还没有被送过
然后 先开始遍历一遍
令 满足 !used[a[i]] 的人送礼物
然后遍历第二次
令 满足 !vis[i]的人送给 s里面 的人
此时会有两种情况
1.如果没送到 i 没关系
2. 如果送到了i 那么就把 i的礼物送给a[i] (这个一定被另一个人pos[a[i]]送了礼物)
令 pos[a[i]]送礼物给i 就可以解决这种情况啦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值