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);
}
相关文章
相关标签/搜索