cf1348 E. Phoenix and Berries(dp)

https://codeforces.com/contest/1348/problem/E

题意:

\(n\) 棵树,第 \(i\) 棵树上有 \(a_i\) 个红果和 \(b_i\) 个蓝果。一个篮子的容量为 \(k\) ,一个篮子里的果子有两种可能:

第一种:来自同一棵树,可以异色;

第二种:同色,但可以来自不同的树。

求能够被装满的篮子数量的最大值(不必用完所有梅子)

\(n,k\le 500\),$a_i,b_i\le 1e9 $

思路:

首先,如果无视规则,最多能放满 \(\lfloor\frac{\Sigma_{i=1}^n(a_i+b_i)}{k}\rfloor\) 个篮子(这是理论最大值)。如果不采用把同一棵树上的红蓝果放一起的放法,只把相同颜色的放一起,能放满 \(\lfloor\frac{\Sigma_{i=1}^na_i}{k}\rfloor + \lfloor\frac{\Sigma_{i=1}^nb_i}{k}\rfloor\) 。发现后者至多比前者少1,相当于把相同颜色放一起后,再选一棵树来放满一个异色篮子。
另有一种 \(O(nk)\) 做法,等我学会了来更新

注意 \(n,k\) 都比较小,可以用 \(O(nk^2)\) 的 dp

一棵树最多产生一个异色篮子。因为如果有两个异色篮子,就一定能变成一个同色篮子和一个异色篮子。

\(bool\) \(dp[i][j]\) 表示只考虑前 \(i\) 棵树(后面的树就当不存在),能否有 \(j\) 个未分配的红果(即未被放进任何一种篮子)。如果未分配的红果数大于等于 \(k\) ,就可以拿出来填充更多的篮子,所以 \(j<=k-1\) 。同理,未分配的蓝果数也不会超过 \(k-1\) 。所以篮子数 \(ans=\lfloor \frac{果子总数-j}{k} \rfloor\) ,不需要考虑蓝果了

假设 \(dp[i][j]=1\) ,那么第 \(i+1\) 棵树可能有两种情况:

完全没有异色篮子,那么剩下 \((a_{i+1}+j)\%k\) 个红果未配对。 \(dp[i+1][(a_{i+1}+j)\%k]=1\)

有一个异色篮子,其中有 \(l\) 个红果,\(0\le l\le min(k,a_{i+1})\)。如果蓝果的数量够用也就是 \(l+b_{i+1}>=k\) ,那么 \(dp[i+1][(a_{i+1}-l+j)\%k]=1\)

最后输出满足 \(dp[n][j]==1\)\(ans\) 的最大值

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int N = 510;
int a[N], b[N];
bool dp[N][N];

signed main()
{
    int n, k; ll tot = 0;
    cin >> n >> k;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i];
        tot += a[i] + b[i];
    }

    dp[0][0] = 1;
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < k; j++) if(dp[i][j])
        {
            dp[i+1][(a[i+1]+j)%k] = 1;
            for(int l = 0; l <= min(k, a[i+1]); l++)
                if(l + b[i+1] >= k)
                    dp[i+1][(a[i+1]-l+j+k)%k] = 1;
        }
    }

    ll ans = 0;
    for(int j = 0; j < k ; j++)
        if(dp[n][j]) ans = max(ans, (tot-j)/k);
    cout << ans << '\n';

    return 0;
}

posted @ 2021-10-19 22:18  Bellala  阅读(20)  评论(0)    收藏  举报