Codeforce 370C Mittens 巧妙数学题

这道题目我一开始想错了,觉得只要排好序,再从头到尾把可以相互交换的进行下交换就可以了。。。事实证明是错的。正确的解法比较巧妙,而且写法非常好,值得学习

首先,要注意的一个规律是,假如最大的颜色数字出现的次数 为 c, c超过了n的一半,则必定无法将所有的人的颜色交换成两两不同的,而且此时颜色不同的人的数目也已经出来了

就是 (n-c)*2,于此,也很容易得出,一旦c没有超过n的一半,则肯定能够把所有人都排成不一样的,(先把相同颜色的找另一类相同颜色的互换,某一类不够了,再找另一类的来继续补充一下即可)此时的答案就是n。

进一步分析,如果是第一种情况,则一个很巧妙的处理方法就是从1到n遍历,如果当前i的颜色为颜色最多的那个颜色,则,先输出i颜色,再从非c颜色里面找不同的来匹配,当然最多只能找d个,d=n-c,如果找完d个了,就只能输出一样的颜色了,代表该人无法颜色不同。。。如果当前颜色不为i那个颜色,则先输出该颜色,再输出那个最多的颜色。

第二种情况的话,先对颜色进行排序,把相同颜色的放在一起,然后有个很巧妙的处理方法,就是某颜色的另一半=(i+c)%n.color,这个好好想想就能明白,既能遍历完整个n,又能保证不会遇到重复色(因为相同颜色在同一堆,而且这一堆的数目最大为c,所以+c再对n取模,是绝对不会匹配大到相同的颜色的)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
    int date;
    int id;
    int other;
} p[5005];
bool cmp(node a,node b)
{
    return a.date<b.date;
}
bool cmp2(node a,node b)
{
    return a.id<b.id;
}
int c[105];
int main()
{
    int n,m,i,j;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        memset(c,0,sizeof c);
        for (i=1;i<=n;i++)
        {
            scanf("%d",&p[i].date);
            p[i].id=i;
            c[p[i].date]++;

        }
        int maxn=0,index;
        for (i=1;i<=m;i++)
        {
            if (maxn<c[i])
            {
                maxn=c[i];
                index=i;
            }
        }
        if (maxn*2>n)
        {
            printf("%d\n",(n-maxn)*2);
            int d=n-maxn;
            j=0;
            for (i=1;i<=n;i++)
            {
                if (p[i].date==index)
                {
                    printf("%d ",index);
                    if (d>0)
                    {
                        for (j++;j<=n && p[j].date==index;j++); //这里是个细节,j每次先要++
                        printf("%d\n",p[j].date);
                        d--;
                        
                    }
                    else
                        printf("%d\n",index);
                }
                else
                {
                    printf("%d %d\n",p[i].date,index);
                }
            }
        }
        else
        {
            printf("%d\n",n);
            sort(p+1,p+1+n,cmp);
            for (i=1;i<=n;i++)
            {
                int loc=i+maxn;
                loc%=n;
                if (loc==0) loc=n;
                p[i].other=p[loc].date;
            }
            sort(p+1,p+1+n,cmp2);
            for (i=1;i<=n;i++)
            {
                printf("%d %d\n",p[i].date,p[i].other);
            }
        }

    }
    return 0;

}

 

posted @ 2013-12-11 22:21  KRisen  阅读(312)  评论(0编辑  收藏  举报