题目如下:
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
小红正在研究如何把符卡组合出尽可能大威力的组合魔法。
小红共有 n 种符卡可以选择,每种符卡最多只能选择一次,每个符卡的魔力消耗为 ai,威力为 bi。
如果将多个符卡进行组合,则可以发动一个组合魔法。组合魔法的魔力消耗为选择的符卡的魔力消耗的总和,其威力为选择的符卡的威力的总和。
小红必须保证最终符卡的魔力消耗总和为 k 的倍数,否则小红将受到魔力反噬而发动魔法失败。
小红想知道,自己能发动的组合魔法最大的威力是多少?输入描述:
第一行输入两个正整数 n 和 k ,用空格隔开。
接下来的 nnn 行,每行输入两个正整数 ai和 bi,用空格隔开。
数据范围:
1≤n,k≤1000
1≤ai,bi≤1e9输出描述:
如果小红无论如何也组合不了能发动的魔法,则输出-1。 否则输出最大的威力值。示例1
输入
2 3 1 2 2 1输出
3说明
两个符卡都选上,融合出的魔法消耗为3,是3的倍数。威力是3。示例2
输入
2 2 1 2 2 1输出
1说明
选择第二个符卡,消耗为2,是2的倍数。威力是1。示例3
输入
3 4 1 2 5 3 1 4输出
-1说明
显然,无论如何都组合不出消耗为4的倍数的魔法。
首先我们先看一下题:
可以发现有很明显的取与不取的关系——》DP问题(01背包)
然后我们再来看一下数据范围,如果我们背包容量单纯按数据走,数组根本就放不下!!!
那怎么办,明明是DP问题
发现还有一个条件:魔力消耗总和为 k 的倍数
我们可以发现 1 与 k+1的容量其实是等价的(在结果上)
如何理解上面的话呢?
容量:
k
2*k
3*k
....
n*k
我们要的是上述容量下威力的最大值,所以在此条件下,上述容量下是”等价的“
也可以说是不影响答案的!!!
所以在DP过程中,我们需要对容量进行取模操作,剩下的和普通DP(01背包)一样
AC代码如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0), cout.tie(0)
const int N = 1009;
ll dp[N][N];
ll s[N][2];
const int inf = 1e9+7;
int main()
{
ios;
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>s[i][0]>>s[i][1];
for(int i=0;i<=n;i++)for(int j=0;j<=k;j++)
dp[i][j]=-inf;
dp[0][0] = 0;
for(int i = 1;i<=n;i++)
{
int a,b;
a = s[i][0];
b = s[i][1];
a%=k;
for(int j = k-1;j>=0;j--)
{
dp[i][j] = max(dp[i-1][j],dp[i-1][(j-a+k)%k]+b);
}
}
if(dp[n][0])
cout<<dp[n][0];
else
cout<<-1;
}
(:
最后,感谢您的阅读!!!
(:
我忍了三年,就是要等一个机会。——《英雄本色》