Codeforces Round #733 (Div. 1 + Div. 2) D. Secret Santa
阿新 • • 發佈:2021-07-18
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; }