题目链接
https://www.luogu.org/problemnew/show/P2062
题目大意
给定一个长度为 的序列,将其分为若干个序列,每个序列的长度必须大于该序列中的最大值,问最多可以划分成几个序列
解题思路
首先对该序列进行排序,然后进行动态转移
设
表示前
个数可以组成的最多序列的长度,我们可以发现
只和
有关系,那么我们可以得到状态转移方程
但是由于数据太大,这样子是会超时的,所以我们需要用一个数组 来维护 之间的最大值,所以可以得到新的方程
DP代码
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001],n,now,ans,maxs,f[1000001],g[1000001];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+1+n);//排序
for(int i=1;i<=n;i++)
{
if(i>=a[i]) f[i]=g[i-a[i]]+1;//动态转移
g[i]=max(f[i],g[i-1]);//保存最大的f[k]
}
printf("%d",f[n]);
}
然后我们学校的一位大佬用了贪心过了,我也不知道原理,就在这里放一下代码吧
贪心代码
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001],n,now,ans,maxs;
bool cmp(int x,int y){return x>y;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+1+n,cmp);
now=a[1];maxs=a[1];
for(int i=1;i<=n;i++)
{
if(a[i]<now)
now=a[i],maxs=a[i];
--now;
if(!now)
now=a[i],maxs=a[i],ans++;
}
printf("%d",ans);
}
时间复杂度
由于上述方法都是拍了序后循环了一遍 ,所以时间复杂度都是