1. 程式人生 > 實用技巧 >【Codeforces Round #662 (Div. 2) 】C. Pinkie Pie Eats Patty-cakes 貪心

【Codeforces Round #662 (Div. 2) 】C. Pinkie Pie Eats Patty-cakes 貪心

題目連結

題意

給出 \(n\) 個數字,每個數字都大於等於 1,小於等於 n。現在問怎麼排列使得任意兩個相同的數字之間的最小距離最大。

思路

看完就直接想到了二分,二分最小距離。

關鍵就在check函式怎麼寫?

首先按照出現次數從大到小排序,優先處理出現次數多的。

依次遍歷數字,對於當前數字,找到第一個可以放的位置,然後該位置 +=x(x是當前檢驗的最小距離),即接下來這個數字可以放的位置,如果新得到的位置已經有數字,那麼向後遍歷找到第一個沒有數字的位置。

如果該數字沒有放完,並且此時可以放的下標已經超過 n 了,那麼當前距離就不合法。

但是 WA 了。
比如這個樣例:

1
10
1 1 2 2 3 3 4 4 4 4

在檢驗 x 為 2 的時候,會形成下面的排列:

4 1 4 1 4 2 4 2 3 3

這是不合法的。最後會輸出0。

但是可以這樣排列:4 3 2 4 3 1 4 2 1 4,答案應該是2。

然後二分我想不到怎麼放了。

看著樣例突然想到了模擬:

我們按照最大的出現次數分組,每組最初都有一個最大出現次數的數字。

比如上面的樣例,有4 個 4,那麼我們分成 4 組,。

①:4

②:4

③:4

④:4

接下來我們按照出現次數從高到低的數字往每個組裡放數字:1 2 3。

①:4,1,2

②:4,1,3

③:4,2,3

④:4

答案就是 2。

這裡產生一個問題,也就是最後一組到底要不要放數字?

乍一看不放數字是最好的,但是會出問題,比如:

2 2 2 1 1 1 3 3 3

如果不放會變成如下這樣:

①:1,2,2,3

②:1,2,3,3

③:1,

這樣排列相同的就直接在一起了。

原因就是有多個出現次數相同的,那麼可以這樣放:如果該數字的出現次數和最大次數相同,那麼最後一組就應該放,否則最後一組不放。

此時答案為長度最短的一個組的長度 - 1。

程式碼

/*
 * @Autor: valk
 * @Date: 2020-04-04 14:56:12
 * @LastEditTime: 2020-09-16 19:47:11
 * @Description: 如果邪惡  是華麗殘酷的樂章 它的終場 我會親手寫上 晨曦的光 風乾最後一行憂傷 黑色的墨 染上安詳
 */

#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;

int arr[N], cnt[N];
int main()
{
    int _;
    scanf("%d", &_);
    while (_--) {
        memset(cnt, 0, sizeof(cnt));
        int n;
        scanf("%d", &n);
        int maxn = -1, num = -1;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &arr[i]);
            cnt[arr[i]]++;
            maxn = max(maxn, cnt[arr[i]]);
        }
        int rel = n;
        for (int i = 1; i <= n; i++) {
            if (cnt[arr[i]] == maxn) {
                rel--;
            }
        }
        sort(arr + 1, arr + 1 + n);
        n = unique(arr + 1, arr + 1 + n) - arr - 1;
        for (int i = 1; i <= n; i++) {
            if (cnt[arr[i]] == maxn) {
                num++;
            }
        }
        printf("%d\n", num + rel / (maxn - 1));
    }
    return 0;
}
/*
1
10
1 1 2 2 3 3 4 4 4 4
4
7
1 7 1 6 4 4 6
*/