CodeForces_1348E Phoenix and Berries(动态规划)

Phoenix and Berries

time limit per test:2 seconds
memory limit per test:256 megabytes
Problem Description

Phoenix is picking berries in his backyard. There are n shrubs, and each shrub has ai red berries and bi blue berries.

Each basket can contain k berries. But, Phoenix has decided that each basket may only contain berries from the same shrub or berries of the same color (red or blue). In other words, all berries in a basket must be from the same shrub or/and have the same color.

For example, if there are two shrubs with 5 red and 2 blue berries in the first shrub and 2 red and 1 blue berries in the second shrub then Phoenix can fill 2 baskets of capacity 4 completely:

  • the first basket will contain 3 red and 1 blue berries from the first shrub;
  • the second basket will contain the 2 remaining red berries from the first
    shrub and 2 red berries from the second shrub.

Help Phoenix determine the maximum number of baskets he can fill completely!

Input

The first line contains two integers n and k ( 1 ≤ n , k ≤ 500 1≤n,k≤500 1n,k500) — the number of shrubs and the basket capacity, respectively.

The i-th of the next n lines contain two integers a i a_i ai and b i b_i bi ( 0 ≤ a i , b i ≤ 1 0 9 0≤a_i,b_i≤10^9 0ai,bi109) — the number of red and blue berries in the i-th shrub, respectively.

Output

Output one integer — the maximum number of baskets that Phoenix can fill completely.

Sample Input

2 4
5 2
2 1

Sample Output

2

题意

n棵树,每棵树上有ai个红果实和bi个蓝果实。有可以装k个果实的篮子,一个篮子只能放同种颜色或同一棵树上的果实。求最多可以放满多少个篮子?

题解

显然大多数篮子内的果实都是同颜色的,最多只有n个篮子内的果实是不同色的(若同棵树有多个篮子装的不同色果实,可以将其转为为多个同色篮和一个不同色)。所以只需要考虑每棵树不同颜色的那个篮子的组成。
d p [ i ] [ j ] dp[i][j] dp[i][j]为考虑第 i i i棵树果实装完后剩下的红果实数量为 j j j能装满的最大篮子数。
(蓝果实呢?设 d p [ i ] [ j ] [ z ] dp[i][j][z] dp[i][j][z] z z z代表剩余蓝果实的话,复杂度为 50 0 4 500^4 5004,显然会超时,实际上一个 j j j对应的剩余蓝果实数量是唯一的,等于 果 实 总 数 − d p [ i ] [ j ] ∗ k − j 果实总数-dp[i][j]*k-j dp[i][j]kj)。

状态转移:设第 i i i棵树之前的红蓝果实总数为 s u m sum sum
枚举不同颜色的那个篮子的组成,由 s 1 s1 s1个红果实和 k − s 1 k-s1 ks1个蓝果实组成。
则考虑之前的剩余果实,剩余未装篮的红果实有 n u m 1 = j + a [ i ] − s 1 num1 = j+a[i]-s1 num1=j+a[i]s1个,未装篮的蓝果实数量为 n u m 2 = b [ i ] − ( k − s 1 ) + s u m − d p [ i ] [ j ] ∗ k − j num2 = b[i]-(k-s1)+sum-dp[i][j]*k-j num2=b[i](ks1)+sumdp[i][j]kj

所以递推式为
d p [ i + 1 ] [ n u m 1 % k ] = m a x ( d p [ i + 1 ] [ n u m 1 % k ] , d p [ i ] [ j ] + 1 + n u m 1 / k + n u m 2 / k ) dp[i+1][num1\%k] = max(dp[i+1][num1\%k], dp[i][j]+1+num1/k+num2/k) dp[i+1][num1%k]=max(dp[i+1][num1%k],dp[i][j]+1+num1/k+num2/k)

然后考虑不存在不同色篮的转移的情况即可。

取dp[i][j]最大值即为所求。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 520;
const int mod = 1000000007;
LL dp[maxn][maxn];
int a[maxn], b[maxn];

int main()
{
    int n, k, i, j, k2, s1;
    LL sum = 0, mx = 0;
    memset(dp, -1, sizeof(dp));
    scanf("%d %d", &n, &k);
    k2 = 2*k;
    for(i=0;i<n;i++)
        scanf("%d %d", &a[i], &b[i]);
    dp[0][0] = 0;
    for(i=0;i<n;i++)
    {
        for(j=0;j<k;j++)
        if(dp[i][j]>=0){
            int b1 = sum-dp[i][j]*k-j;
            for(s1=1;s1<=a[i] && s1<k;s1++)
            if(b[i]+s1>=k)
            {
                int b2 = b1+b[i]-(k-s1);
                int a2 = j+a[i]-s1;
                dp[i+1][a2%k] = max(dp[i+1][a2%k], dp[i][j]+b2/k+a2/k+1);
            }
            dp[i+1][(j+a[i])%k] = max(dp[i+1][(j+a[i])%k], dp[i][j]+(j+a[i])/k+(b1+b[i])/k);
        }            
        sum += a[i]+b[i];
    }
    for(i=0;i<=n;i++)
        for(j=0;j<=k;j++)
            mx = max(dp[i][j], mx);
    printf("%I64d\n", mx);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值