【牛客小白月赛27:贪心 | DP |(详解)】B:乐团的派对

乐团派对

https://ac.nowcoder.com/acm/contest/6874/B

牛客小白月赛27:B题 乐团的派对

【难度】


鄙人不才,WA了8发。。

【题意】

你有 个人,**每个人有能力值 ,表示该人所在的队伍人数必须大于等于 **

保证每个人都被分进一个队的情况下,队伍数量最多是多少?无解输出

【数据范围】


【样例输入】


4
2 1 2 1

【样例输出】

3

【解释】

队伍1:第一个人、第三个人
队伍2:第二个人
队伍3:第三个人

【思路】

(一)首先考虑贪心

首先判断可行性。易得,若 则无解,输出
接下来,人怎么分组?
既然是贪心,易想到我们需要对能力值进行排序。

(1)逆序贪心?

【做法】
我们把 进行循环遍历。
若对于第 个人能力值为 是接下里还没分好组的人。
接下来,我们选择 ,把这些人组成一支队伍。
,则可以划分队伍,因为易得
,则无法划分队伍,就把他们合并到人数最多的队伍。

【结果】
可以AC


有反例可以
比如
按照该贪心算法,分组为,为两组。
但是正确的分组应该为 ,为六组。
牛客数据水了

【结论】

(2)顺序贪心?

【做法】
我们把 进行循环遍历。
若对于第 个人能力值为 是接下里还没分好组的人。
接下来,我们选择 ,把这些人组成一支队伍。
,则无法划分队伍,就把他们合并到人数最多的队伍。

【结果】


该算法 当然不一定成立。
比如分组
按该算法的分组为 ,为两组。但是分组不满足题目要求呀!
但是正确的分组应该为 ,为一组。

【结论】

(3)改良顺序贪心?

【做法】
我们把 进行循环遍历。
若对于第 个人能力值为 是接下里还没分好组的人。
接下来,我们选择 ,把这些人组成一支队伍。
,我们继续选择
直到第一个合法的 满足
若 找不到合法的 ,则这些人与最大人数的队伍合并。


该算法
比如分组
按该算法, 枚举到时,目前分组为
但是遇到 ,我无法选出5个人来,也无法在某个已有团队中直接把这个人给塞进去。
我们还要再计算最少数目的已有团队,使得团队总人数
怎么变成背包问题了??这可是贪心做法!

【结论】

(4)正解贪心

【做法】

升序排序后,**我们先把 安排掉**,易得至少要 个人。
我们安排 这些下标的人: 成立,所以该选择一定是合法的、最贪心的。

接下来,我们把 进行循环遍历。与做法3的贪心选择相同:

若对于第 个人能力值为 是接下里还没分好组的人。
接下来,我们选择 ,把这些人组成一支队伍。
,我们继续选择
直到第一个合法的 满足
若 找不到合法的 ,则这些人与最大人数的队伍合并。

【核心代码】

时间复杂度:
就是排序+for循环的时间复杂度。

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 1e5+50;
int aa[MAX];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&aa[i]);
    sort(aa+1,aa+1+n);
    int ren = 1;            /// ren表示目前该队伍中有多少人,默认值为 1
    int ans = 1;
    if(aa[n] > n)printf("-1");
    else{
        for(int i=1;i<=n - aa[n];++i){
            while(i<=n - aa[n] && ren < aa[i]){
                int cha = aa[i] - ren;
                ren += cha;
                i += cha;
            }
            if(i > n - aa[n])break;    /// 找不到合法的‘k’,与最大队伍合并,答案不变
            ans++;            /// 找到了合法的‘k’,新的队伍产生
            ren = 1;
        }
        printf("%d",ans);
    }
    return 0;
}

(二)其次考虑DP做法

首先,我们一样升序排序。
对于第 个人我们可以把它合并在第 个人的团队里面(如果存在的话)。
或者,我们**选择 下标的人拉成新的一个队伍**。
当然这时我们选择的是 ,稍微想一想就能得到了。

那么状态转移方程就得到了:


【感谢热心网友的Hack!】

【核心代码】

时间复杂度:
就是排序+for循环的时间复杂度。
人的本质是复读机

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 2e5+50;
int aa[MAX];
int dp[MAX];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&aa[i]);
    sort(aa+1,aa+1+n);
    int t;
    for(int i=1;i<=n;++i){
        int di = (i - aa[i]);
        t = 0;                        /// 选 [di+1,i]的人的时候的dp[i]的值
        if(di >= 0)t = dp[di] + 1;
        dp[i] = max(t,dp[i-1]);       /// 向左合并
    }
    printf("%d",t==0 ? -1 : t);       /// 为了保证合法,最后一支队伍要选择区间[n-a[n]+1,n]的范围
    return 0;
}
全部评论
大佬分析的很到位,但是dp做法好像有瑕疵,可以试试 3 1 1 3 这组数据(菜鸡一枚,有错轻喷)
1
送花
回复
分享
发布于 2020-08-24 21:58
12 6 6 6 6 6 6 6 1 1 1 1 1 这组样例我可以hack多少人 _(;3亅<)_
点赞
送花
回复
分享
发布于 2020-08-23 17:39
网易互娱
校招火热招聘中
官网直投

相关推荐

感觉这一周太梦幻了,就像一个梦,很不真实~~~感觉这个暑期,我的运气占了99成,实力只有百分之一4.15上午&nbsp;腾讯csig&nbsp;腾讯云部门,面完秒进入复试状态4.16下午&nbsp;美团优选供应链部门,4.18上午发二面4.17晚上&nbsp;阿里国际一面,纯拷打,面完我都玉玉了4.18下午&nbsp;阿里国际二面,是我们leader面的我,很轻松~~4.18晚上&nbsp;约了hr面4.19上午&nbsp;hr面,下午两点口头oc4.19晚上&nbsp;意向书说起来我的暑期好像一次都没挂过~~~~~难道我是天生面试圣体?----------------------------------------------------------------------六个月前,我还是0项目0刷题,当时想的是先把论文发出来再去找实习。结果一次组会,老师打破了我的幻想(不让投B会,只让投刊或者A)我拿头投啊!!!然后就开始物色着找实习,顺便做完了mit的6.s081,但是基本上还是没刷过题目-----------------------------------------------------------------------11月&nbsp;&nbsp;一次偶然的机会,面进了某个耳机厂的手环部门,大概是做嵌入式的,用的是CPP。12月&nbsp;莫名其妙拿到了国创的面试机会,0基础四天速成java基础!居然也给我面过了hhhhh,可能是面试没写题吧入职国创后的几个月,一直没活,天天搁那看剧,都快忘了还有暑期实习这回事了~~~~命运的齿轮在2.26开始转动,因为这一天美团开了,我开始慌了,因为那时的我什么都不会。lc,八股,sql全部是0进度。然后就开始了女娲补天,上班刷题,下班继续做之前的开源,顺便学一学八股。3月到现在,lc也刷到快200了,一天最多提交了47次~~~~~~~~~~八股根据别人的面经总结和博客,写了快十万字的笔记~~~~~~~~~~简历上的实习经历和开源,也努力去深挖了,写了几万字的记录~~~~~~所以面试的时候,基本上都能cover了,面试官问到的基础基本都会,不基础的我就把他往我会的地方引。结果好像还不错,基本上每个面试官评价都挺好的emmmmmmmm
投递阿里巴巴等公司10个岗位
点赞 评论 收藏
转发
12 1 评论
分享
牛客网
牛客企业服务