WA11到死......
题面
题意
给定 n 个数 m[i],每个 m[i] 都在 [1,k] 的范围内
再给定 k 个数 c[i]
要求将所有的 m[i] 进行分组
c[i] 表示每组中大于等于 i 的数不超过 c[i] 个
问最少能分几组,并输出分组方案
解题思路
自己的贪心思路错了,昨晚一个多小时就在WA11上挣扎
直到现在看懂了别人的代码后……才知道有多奇妙
首先要求出最小分组 q
引入新数组 ar,让 ar[i] 表示数组 m 中大于等于 i 的数字的个数
又因为 c[i] 数组表示每个分组大于等于 i 的数字的最大个数
所以就能得到,单对于数字 i 而言,最小分组数为 ar[i] 除以 c[i] 向上取整
写作 ceil(1.0*ar[i]/c[i])
或者 (ar[i]+c[i]-1)/c[i]
最后,让答案分组 q 在这些最小分组中取大即可
得出最小分组 q 后
贪心可得,将数组 m 进行排序后
将 m[1], m[2], m[3]... m[n] 循环放入组 T[1], T[2] ... T[q], T[1], T[2] ... 即可得出分组方案
即对于第 i 组 T[i] 而言,它所包含的数为 m[i], m[q+i], m[2q+i], m[3q+i] ...
根据上面对于 q 的解法,能够保证同一组中的数不会与题意产生冲突
ps. 虽然根据 ar 和 c 数组的定义,m 数组应该是从大到小排序后,从较大的数字开始循环放入的,但实际上从小到大也是可行的
完整程序
(156ms/2000ms)
#include<bits/stdc++.h>
using namespace std;
int m[200050],c[200050],ar[200050];
vector<int> v[200050];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int n,k,i,q=1;
cin>>n>>k;
for(i=1;i<=n;i++)
{
cin>>m[i];
ar[m[i]]++; //先让ar数组表示等于i的数字个数
}
for(i=1;i<=k;i++)
cin>>c[i];
for(i=k;i;i--)
{
ar[i]+=ar[i+1]; //i位置依次加上后面的数量,表示大于等于i的数字个数
q=max(q,(ar[i]+c[i]-1)/c[i]);
}
sort(m+1,m+1+n/*,less<int>()*/); //对m数组排序,可选从大到小
for(i=1;i<=n;i++)
v[i%q].push_back(m[i]); //循环放入vector
cout<<q<<'
';
for(i=0;i<q;i++)
{
cout<<v[i].size();
for(int it:v[i])
cout<<' '<<it;
cout<<'
';
}
return 0;
}