Codeforces 1133E - K Balanced Teams - [DP]

題目連接: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;
}
相關文章
相關標籤/搜索