codeforces - 723C 题解

题意:给定一个歌曲演唱的序列,第i个数字代表第i首歌由ai号乐队演唱;用最少的操作将这些歌改成1-m号乐队演唱,且每个乐队演唱歌曲数的最小值最大。问操作数

问题解法:首先分析如何让最小值最大,有两种方式来提升最小值,第一种是将1-m范围外的乐队演唱的歌分给1-m范围内的演唱数最小的乐队,第二种是将1-m内演唱数较大的乐队的歌分一些给1-m内演唱数较小的乐队。所以题目的贪心策略也就基本确定了

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<climits>
 4 using namespace std;
 5 int a[10001];
 6 int b[10001]={};
 7 int n,m;
 8 int board;
 9 bool check()
10 {
11     for(int i=1;i<=m;i++)
12     {
13         if(b[i]<board)
14         {
15             return true;
16         }
17     }
18     return false;
19 }
20 int main()
21 {
22     cin>>n>>m;
23     for(int i=1;i<=n;i++)
24     {
25         cin>>a[i];
26         if(a[i]<=m)
27         {
28             b[a[i]]+=1;
29         }
30     }
31     int res1,res2=0;
32     board=n/m;
33     for(int i=1;i<=n;i++)
34     {
35         if(a[i]>m)
36         {
37             for(int j=1;j<=m;j++)
38             {
39                 if(b[j]<n/m)
40                 {
41                     b[j]+=1;
42                     a[i]=j;
43                     res2+=1;
44                     break;
45                 }
46             }
47         }
48     }
49     while(check())
50     {
51         for(int i=1;i<=n;i++)
52         {
53             if(b[i]>board)
54             {
55                 for(int j=1;j<=m;j++)
56                 {
57                     if(b[j]<board)
58                     {
59                         for(int k=1;k<=n;k++)
60                         {
61                             if(a[k]==i)
62                             {
63                                 a[k]=j;
64                                 b[i]-=1;
65                                 b[j]+=1;
66                                 res2+=1;
67                                 break;
68                             }
69                         }
70                         if(b[i]<=board)
71                         {
72                             break;
73                         }
74                     }
75                 }
76             }
77         }
78     }
79     res1=INT_MAX;
80     for(int i=1;i<=m;i++)
81     {
82         res1=min(res1,b[i]);
83     }
84     cout<<res1<<" "<<res2<<endl;
85     for(int i=1;i<=n;i++)
86     {
87         cout<<a[i]<<" ";
88     }
89     return 0;
90 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值