原题:3583. 整数分组
3583. 整数分组
给定 n 个整数 a1,a2,…,an。
现在,请你从中挑选一些数,并将选出的数进行分组。
要求:
- 选出的数最多划分为 k 组(至少 1 组)。
- 同一组内,任意两数之差的绝对值不超过 5。
- 所选出的数尽可能多。
请问,最多可以选出多少个数进行分组?
输入格式
第一行包含两个整数 n 和 k。
第二行包含 nn 个整数 a1,a2,…,an。
输出格式
输出一个整数,表示可以选出的最大整数数量。
数据范围
1≤k≤n≤5000,
1≤ai≤10^9
输入样例1:
5 2
1 2 15 15 15
输出样例1:
5
输入样例2:
6 1
36 4 1 25 9 16
输出样例2:
2
输入样例3:
4 4
1 10 100 1000
输出样例3:
4
思路:首先想到的是贪心,后面列举了反例,比如k=1的时候很容易证明错误。之后想到了dp,首先定义dp[i][j]代表前i+1个数分j组最多能选取的数量。则出现两种情况就是若第i个数不选则dp[i][j]=dp[i-1][j];若选择第i个数,则查询它所能包括的区间,若该区间没有和其他区间重叠则dp[i][j]=dp[m][j-1]+i-m;若和其他区间重叠则将重叠部分分给后区间也是dp[i][j]=dp[m][j-1]+i-m;
综上所述,dp[i][j]=dp[i-1][j]//不选 =dp[m][j-1]+i-m;注意:第0个数有一个以上的区间则能选它,即为1。
代码:
向前版本:
#include <bits/stdc++.h>
using namespace std;
const int N = 5010;
int nums[N];
int dp[N][N];
int main()
{
int n, k;
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> nums[i];
}
sort(nums, nums + n);
for (int j = 1; j <= k; j++)
{
dp[0][j] = 1;
}
for (int i = 1; i < n; i++)
{
for (int j = 1; j <= k; j++)
{
dp[i][j] = max(dp[i][j], dp[i - 1][j]); //不选
int m = i - 1;
while (m >= 0 && (nums[i] - nums[m]) <= 5)m--;
dp[i][j] = max(dp[i][j], ((m<0)?0:dp[m][j - 1]) + i - m); //分区
}
}
cout << dp[n - 1][k] << endl;
return 0;
}
向后版本:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5010;
int n, m;
int w[N];
int f[N][N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
sort(w + 1, w + n + 1);
for (int i = 1, k = 1; i <= n; i ++ )
{
while (w[i] - w[k] > 5) k ++ ;
for (int j = 1; j <= m; j ++ )
f[i][j] = max(f[i - 1][j], f[k - 1][j - 1] + (i - k + 1));
}
printf("%d\n", f[n][m]);
return 0;
}