【牛客小白月赛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

相关推荐

xdm&nbsp;早上喝奶茶差点喷出来。事情是这样的,我们班有个哥们儿,简称&nbsp;L,去年秋招拿了字节sp,专业方向是后端。我们当时都震惊:这哥们儿平时课上从来不发言,期末小组作业基本是划水的那种,刷题平台&nbsp;commit记录我点进去看过,绿格子稀稀拉拉。但他面试一路绿灯。一面二面三面&nbsp;hr&nbsp;面,全过,给的还是sp。当时班级群里恭喜他的、问他经验的、约饭的,热闹了一周。他说自己"运气好,准备充分"。我们都信了,直到三月初他入职。入职第二周开始,班里另一个进字节的同学W(在隔壁组的)开始跟我他的不对劲。一开始是写代码慢,后来写不出来,再后来是组里&nbsp;mentor&nbsp;让他fix&nbsp;一个简单&nbsp;bug&nbsp;都搞了一下午没动静。最离谱的是上周。W&nbsp;说他们大部门搞了个新人分享会,让新人讲一下自己负责模块的设计思路。L&nbsp;上去讲了&nbsp;20分钟,全程念稿子,问答环节别人随便问一个"那你这里为什么用&nbsp;Redis&nbsp;不用&nbsp;Memcached",他直接卡&nbsp;30秒说"这个我回去再确认一下"。会后他&nbsp;mentor&nbsp;直接找&nbsp;leader&nbsp;谈,leader&nbsp;找&nbsp;hr&nbsp;谈,hr调出了他面试录像,全程对比口型和回答节奏,发现他二三面有大量时长在偷偷看屏幕外(推测开了双机位&nbsp;AI&nbsp;答题)。(这段是&nbsp;W后来转述给我的,他自己也是听他组里同事八卦来的)昨天下班前,W&nbsp;告诉我L&nbsp;被辞退了,让他自己走,不走就走仲裁但会发函到学校。L&nbsp;现在已经回学校了,朋友圈仅三天可见。我说真的,我不是个心眼小的人,但是我看到这个消息的时候真的有种"嗯,挺好"的感觉。去年秋招我投字节后端,简历挂。我准备了八个月,背&nbsp;八股&nbsp;+&nbsp;刷&nbsp;500&nbsp;题&nbsp;+项目改了三版,连面试机会都没拿到。班里这哥们儿凭着一个外挂上岸,最后还是被甩出来了。不是说作弊就一定会被发现,但是当面试拿到的&nbsp;offer远远超出真实能力的时候,迟早会有这一天。试用期三个月不是给你过家家的,是真的要写代码、要在会议上回答问题、要扛需求的。我现在反而有点同情他。同情他相信"上岸就是终点"。发出来不是为了嘲笑谁,就是想说给那些正在被身边作弊上岸的同学搞得很&nbsp;emo&nbsp;的&nbsp;uu&nbsp;们听——别急,回旋镖很长,但它一定会回来。你继续刷你的题,写你的项目,背你的八股。该是你的迟早是你的,不是你的早晚还得还回去。xdm&nbsp;共勉。
牛客12588360...:我不想评论面试方式,作弊是绝对不对的,但是你八股加刷题也不过是个做题小子,他穿帮纯粹是他菜,你也没有高明到哪里去
点赞 评论 收藏
分享
评论
18
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务