Codeforces 1342D

WA11到死......


题面

Prob1
Prob2




题意

给定 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;
}
原文地址:https://www.cnblogs.com/stelayuri/p/12785409.html