题意:给定一个歌曲演唱的序列,第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 }