ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #733 (Div. 1 + Div. 2) D. Secret Santa

2021-07-18 12:33:09  阅读:241  来源: 互联网

标签:xia int Codeforces st 733 fer ans Div define


D. Secret Santa

题意

给t组样例
每组样例给n个数
a[1] , a[2] , a[3] ...... a[n]
(t组样例n的总和<=2e5,a[i] <= n)
并且保证a[i] != i
求一个数组p
并且这个数组p为1到n的全排列中的一种方式
求 p[i] == a[i] 的个数最大并且p[i] != i

输出这个个数的最大值和p数组

思路

首先先把可以匹配的匹配了
举个例子
a 6 4 6 2 4 5 1
从头到尾扫一遍
p 6 4 _ 2 _ 5 1

还差3 7没填
然后在考虑怎么安排3 7的位置 使得p[i] != i 
很明显应该
p 6 4 7 2 3 5 1

也就是说题目转换成为了
怎么安排未匹配的数
使得p[i] != i 

这里有个性质
自闭了1h才想出来

假设现在没有匹配的数是 1 2 3 4 5 6 7 
有7个位置要填
_ _ _ _ _ _ _ 

那我1 2 3 4 5 6 7 正序填
7个都冲突出现了p[i] = i 的情况

如果倒叙填
是 7 6 5 4 3 2 1 
只有p[4] 冲突了

那是不是说明了正序填和倒叙填有一种情况
最多只冲突一次
(可以自己多找几组样例看看是不是对的)

如果冲突一次
找到这个数交换一下即可

时间复杂度:O n

#include<bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define re register int
#define pll pair<int,int> 
#define x first 
#define y second 
#define sf(x) scanf("%d",&x)
#define sfl(x) scanf("%lld",&x)
typedef long long ll ;
using namespace std;
const int N = 2e5 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
int t ;
int n ;
int a[N] ; // a数组
bool st[N] ; // 判断这个数有没有出现过
int ans[N] ;  
int s[N] ; // s , ans最后的答案数组
int main()
{
    cin >> t ;
    while(t--)
    {
        cin >> n ;
        
        fer(i,1,n) sf(a[i]) ;
        
        fer(i,1,n) st[i] = ans[i] = 0 ; // 初始化
        
        int cnt = 0 ;
        
        fer(i,1,n) // 把可以匹配的先匹配了
        {
            if(!st[a[i]])
            {
                cnt ++ ;
                st[a[i]] = 1 ;
                ans[i] = a[i] ;
            }
        }
        
        vector<int> q ; // 找到未匹配的数
        fer(i,1,n)
        {
            if(!st[i])
                q.push_back(i) ;
        }
        //fer(i,1,n) cout << a[i] << " " ;
        
        sort(q.begin(),q.end()) ;
        reverse(q.begin(),q.end()) ;
        // 倒叙填一遍
        
        int cnt1 = 0 , cnt2 = 0 ;
        // cnt1为倒叙的冲突个数 , cnt2反之
        
        fer(i,1,n)
        {
            s[i] = ans[i] ;
        }
        // 先让s数组和ans数组相等
        
        // 倒叙填ans数组
        int k = 0 ;
        fer(i,1,n)
        {
            if(!ans[i])
            {
                ans[i] = q[k ++] ;
            }
        }
        
        fer(i,1,n)
        {
            if(ans[i] == i) cnt1 ++ ;
        }
        
        // 正序填s数组
        reverse(q.begin(),q.end()) ;
        k = 0 ;
        fer(i,1,n)
        {
            if(!s[i])
            {
                s[i] = q[k ++] ;
            }
        }
        
        fer(i,1,n)
        {
            if(s[i] == i) cnt2 ++ ;
        }
        
        if(cnt1 > cnt2)
        {
       	// 如果ans数组冲突值大了,把s数组给ans
            fer(i,1,n)
            {
                ans[i] = s[i] ;
            }
        }
        
        // 找到这个冲突值的下标
        int xia = 0 ;
        fer(i,1,n)
        {
            if(ans[i] == i)
            {
                xia = i ;
                break ;
            }
        }
        
        // 然后交换
        fer(i,1,n)
        {
            if(ans[i] == a[xia] && i != xia)
            {
                swap(ans[i],ans[xia]) ;
                break ;
            }
        }
        
        // 最后输出答案
        cout << cnt << "\n" ;
            
        fer(i,1,n) cout << ans[i] << " " ;
        
        cout << "\n" ;
    }
    return 0;
}

标签:xia,int,Codeforces,st,733,fer,ans,Div,define
来源: https://www.cnblogs.com/yueshehanjiang/p/15026239.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有