Comet OJ - Contest #10 B題 沉魚落雁

###題目連接###html

 

題目大意:有 n 個正整數,每一個正整數表明一個成語,正整數同樣則成語相同。同一個正整數最多隻會出現 3 次。ios

求一種排列,使得這個排列中,相同成語的間隔最小值最大,輸出這個最小間隔的最大值。spa

相同成語的間隔爲這二者中間的成語個數。code

特別地,當每種成語都只出現一次時,把最小間隔的最大值視爲 htm

 

分析:blog

一、若成語最大出現的次數是 2 時:好比有兩個不一樣的成語 1  2 ,他們都出現過兩次,那麼爲了使得最小間隔要最大,最好的構造就是兩個 1 的間隔等於兩個 2 的間隔。
get

       1    2     X X X X X    1    2        ( X 表明別的成語)it

這樣就可使得出現過兩次的成語,他們的間隔都相同了,不會有哪個更小。那麼設 res = 只出現一次的成語個數,設 a = 出現爲兩次的成語種類數。io

則 res = n - 2 * a ,答案就是:res + (a - 1)class

 

二、那麼對於成語沒有出現次數爲 2 ,有出現次數爲 3 時,也能夠這樣構造。   1  2  3     X X X    1  2  3   X X     1  2  3

這樣你會發現,1 2 3 這三個成語的最小間隔都同樣,那因爲這裏 X 爲奇數(X=5),分佔兩邊則必有一邊更少,那麼少的這一邊就是最小間隔了。

設 res = 出現一次的成語個數,a = 出現三次的成語種類數。則 res = n - 3 * a,答案就是:res + (a - 1)。

 

三、那麼對於既有兩次的又有三次出現的成語,也能夠用上面的思想構造:

因爲爲了使最小間隔最大,而對於出現三次的成語,最好是一個在最左一個在最右,一個在最中間。而對於出現兩次的成語,因爲沒有 「中間第三個成語」的限制,那麼爲了加大出現三次的成語的間隔數,最好的方法就是先最左最右排完出現三次的成語,而後才排出現兩次的成語。

好比這有出現三次的:1  2  3,出現兩次的  4  5 。

1  2  3   4  5           XX     1  2  3           X X X        4  5   1  2  3

這樣能夠最大限度的保證最小間隔儘可能小且 1 與 1 ,2 與 2 ,3與 3 的最小間隔相同(對於成語出現兩次的也是同樣的,它們間隔都相同)

但這裏有個極限想法:若是出現兩次的成語個數不少,致使它們一直往中間靠攏,可能會使某個出現兩次的成語的間隔會小於出現三次的成語的間隔,則同時求出來而後去 min 便可。

設 res = 出現一次的成語個數,x = 出現兩次的成語種類數,y = 出現三次的成語種類數。

則有:res = n - 2 * x - 3 * y,答案爲:min(res + y + x - 1, res / 2 + x + y - 1)

hhh 而後這個 min 其實沒用,能夠從公式中看出,右邊(成語出現爲三次的最小間隔)必定會小於左邊(成語出現爲兩次的最小間隔)。

 

代碼以下:

#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[100008],b[100008],c[100008], vis[100008];
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int len = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; i++) c[i] = lower_bound(b + 1, b + len + 1, a[i]) - b, vis[c[i]] ++;
    int x = 0, y = 0;
    for (int i = 1; i <= len; i++){
        if (vis[i] == 2) x++;
        else if (vis[i] == 3) y++;
    }
    int res, ans;
    if ((!x) && (!y)){
        ans = n;
    }
    else if (x&&(!y)){
        res = n - 2 * x;
        ans = res + x - 1;
    }
    else if ((!x)&&y){
        res = (n - 3 * y) / 2;
        ans = res + y - 1;
    }
    else{
        res = n - 2 * x - 3 * y;
        //ans = min(res + y + x - 1, res / 2 + x + y - 1);
        ans=res / 2 + x + y - 1;
    }
    printf("%d\n", ans);
}
相關文章
相關標籤/搜索