题目
原题链接
问题描述
化为背包问题来理解,就是说有
    
     
      
       
        n
       
      
      
       n
      
     
    n个物品,每个物品的体积为
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai,价值为
    
     
      
       
        
         b
        
        
         i
        
       
      
      
       b_i
      
     
    bi,此时的背包的容积没有限制,但要求放入背包的物品的总体积要为
    
     
      
       
        k
       
      
      
       k
      
     
    k的倍数时价值才有意义。
 数据范围:
 
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ,
       
       
        k
       
       
        ≤
       
       
        1000
       
      
      
       1\leq n,k \leq 1000
      
     
    1≤n,k≤1000
 
    
     
      
       
        1
       
       
        ≤
       
       
        
         a
        
        
         i
        
       
       
        ,
       
       
        
         b
        
        
         i
        
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         9
        
       
      
      
       1\leq a_i,b_i \leq 10^9
      
     
    1≤ai,bi≤109
 
分析
总体积为
    
     
      
       
        k
       
      
      
       k
      
     
    k的倍数,也就是对
    
     
      
       
        k
       
      
      
       k
      
     
    k取模的结果为
    
     
      
       
        0
       
      
      
       0
      
     
    0,所以我们以
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       dp[i][j]
      
     
    dp[i][j]作为状态,表示处理完第
    
     
      
       
        i
       
      
      
       i
      
     
    i个物品后,总体积对
    
     
      
       
        k
       
      
      
       k
      
     
    k取模为
    
     
      
       
        j
       
      
      
       j
      
     
    j的最大价值。
 状态转移方程为:
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        =
       
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        ,
       
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
       
        [
       
       
        (
       
       
        j
       
       
        +
       
       
        k
       
       
        −
       
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
       
        )
       
       
        %
       
       
        k
       
       
        ]
       
       
        +
       
       
        b
       
       
        [
       
       
        i
       
       
        ]
       
       
        )
       
      
      
       dp[i][j]=max(dp[i-1][j],dp[i-1][(j+k-a[i])\%k]+b[i])
      
     
    dp[i][j]=max(dp[i−1][j],dp[i−1][(j+k−a[i])%k]+b[i])
 需要注意的是,如果不提前处理
    
     
      
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       a[i]
      
     
    a[i],
    
     
      
       
        (
       
       
        j
       
       
        +
       
       
        k
       
       
        −
       
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
       
        )
       
      
      
       (j+k-a[i])
      
     
    (j+k−a[i])所得结果会是一个负值(带负数的取模运算),取模结果也可能会是负数,也就会数组越界,导致结果出错,所以提前处理
    
     
      
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       a[i]
      
     
    a[i]。
 其次,关于边界的设置,
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        0
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        =
       
       
        0
       
      
      
       dp[0][0]=0
      
     
    dp[0][0]=0是肯定的,但对于
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        (
       
       
        0
       
       
        <
       
       
        i
       
       
        <
       
       
        k
       
       
        )
       
      
      
       dp[i][0](0<i<k)
      
     
    dp[i][0](0<i<k)的情况,如果同样置为
    
     
      
       
        0
       
      
      
       0
      
     
    0,在后面的讨论中将会出现问题。
 假设第一个物品的体积为
    
     
      
       
        6
       
      
      
       6
      
     
    6,价值为
    
     
      
       
        10
       
      
      
       10
      
     
    10,
    
     
      
       
        k
       
       
        =
       
       
        10
       
      
      
       k=10
      
     
    k=10,在讨论中会出现
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        1
       
       
        ]
       
       
        [
       
       
        5
       
       
        ]
       
       
        =
       
       
        10
       
      
      
       dp[1][5]=10
      
     
    dp[1][5]=10的情况,因为我们预设了
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        0
       
       
        ]
       
       
        [
       
       
        9
       
       
        ]
       
      
      
       dp[0][9]
      
     
    dp[0][9]是有意义的,但实际上这种情况是没有意义无需参与讨论的。
我们可以将无意义情况置为一个极小值,也可以另外开一个数组来记录它们的情况,后续更新它们的状态。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005;
ll n,k,dp[N][N],a[N],b[N]; 
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
		a[i]%=k;
	}
	for(int j=1;j<=k;j++)dp[0][j]=-1e16;
	for(int i=1;i<=n;i++){
		for(int j=0;j<k;j++)
			dp[i][j]=max(dp[i-1][j],dp[i-1][(j+k-a[i])%k]+b[i]);
	}
	cout<<(dp[n][0]?dp[n][0]:-1)<<endl;
}










