牛客月赛 乐团派对(dp)

题目描述 

音乐是带给大家快乐的存在,而你的目标就是组建若干支乐队,让世界听到你们的演奏!

你目前有n位乐手,每位乐手只能进入一个乐队,但并不是每位乐手都能担大任,因此需要团队合作。第ii位乐手的能力值为a[i]a[i],表示该位乐手所在乐队的人数必须大于等于a[i]。在保证每位乐手都被分进一个乐队的情况下,乐队数量最多可以是多少?

输入描述

第一行一个正整数n,表示乐手人数,n1e5。

第二行n个正整数a[i],表示每位乐手的能力值,a[i]1e9。

输出描述

输出最多的乐队数量。若无法保证每位乐手都被分进一个乐队,则输出-1。

示例1

输入

2 1 2 1

输出

3

思路

贪心的思想是尽可能使a[i]值大的乐手组到一个乐队,按a[i]从小到大排序。构造一个dp数组,dp[i]表示当前人数i所能组成乐队的最大数量。

有转移方程,当i<a[i]时,当前人数构不成乐队,dp[i]=0;当i>=a[i]时,dp[i]=max(dp[i-a[i]],dp[i-a[i]-1,......dp[0])+1;(因为多余的人可以加进本队中,目的是使人数转移到使乐队数最多的人数);

再一边转移一边维护一个前缀max数组,max[i]=max(max[i-1],dp[i]);即当i>=a[i]时,dp[i]=max[dp[i-a[i]]+1;

当dp[n]等于0时,证明无法保证所有人在一个乐队,输出-1。

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int dp[100005];
int maxx[100005];
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        if(a[i]>i)dp[i]=0;
        else dp[i]=maxx[i-a[i]]+1;
        maxx[i]=max(dp[i],maxx[i-1]);
    }
    if(dp[n]==0){
        cout<<"-1"<<endl;
    }
    else cout<<dp[n]<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/mohari/p/13549560.html