题目连接:https://codeforces.com/contest/1133/problem/Cios
题意:c++
给出 $n$ 个数,选取其中若干个数分别组成 $k$ 组,要求每组内最大值与最小值的差值不超过5,求 $k$ 组合起来最多能够放多少个数。数组
题解:spa
将 $a[1 \sim n]$ 从小到大排序,排序后每一个组一定能够视为数组 $a$ 上一段连续区间,code
$f[i][j]$ 表示到第 $i$ 个数为止,前面组成 $j$ 组,最多能够包含多少个数。blog
那么,考虑第 $i$ 个数选取与否,若是不选,那么 $f[i][j]=f[i-1][j]$;排序
若是选,那么必然是第 $i$ 个数所在组人数加上前面那些组人数,假设 $p$ 表示距离 $a[i]$ 左侧最远的那个位置(知足 $a[i]-a[p] \le 5$),$f[i][j]=(i-p+1)+f[p-1][j-1]$。ci
AC代码:get
用lower_bound找 $p$,时间复杂度 $O(n \log n + nk)$。it
#include<bits/stdc++.h> using namespace std; const int maxn=5005; int n,k,ans; int a[maxn]; int f[maxn][maxn]; int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); ans=f[1][1]=1; for(int i=2;i<=n;i++) { int p=lower_bound(a+1,a+i+1,a[i]-5)-a; for(int j=1;j<=min(k,i);j++) { f[i][j]=max(f[i-1][j],(i-p+1)+f[p-1][j-1]); ans=max(ans,f[i][j]); } } cout<<ans<<endl; }
线性维护 $p$,时间复杂度 $O(nk)$。
#include<bits/stdc++.h> using namespace std; const int maxn=5005; int n,k,ans; int a[maxn]; int f[maxn][maxn]; int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); ans=f[1][1]=1; int p=1; for(int i=2;i<=n;i++) { while(p<i && a[i]-a[p]>5) p++; for(int j=1;j<=min(k,i);j++) { f[i][j]=max(f[i-1][j],(i-p+1)+f[p-1][j-1]); ans=max(ans,f[i][j]); } } cout<<ans<<endl; }