传送门:牛客
题目描述:
终于Alice走出了大魔王的陷阱,可是现在傻傻的她忘了带武器了,这可如何是好???这个时候,一个神秘
老人走到她面前答应无偿给她武器,但老人有个条件,需要将所选武器分别放在天平的两端,若天平平衡
则可以将天平上的所有武器拿走,还好这个天平锈迹斑斑,只要两端重量相差小于等于m就会保持平衡,
Alice傻傻的认为越重的武器越好,求Alice最多能拿走的武器总重量。(不限操作次数)
输入:
5 4
1 5 61 65 100
输出:
132
这道dp题感觉还是有点难度的,刚开始我并没有想出来(其实最后也没想出来),看了一遍题解之后恍然大悟(emmm,原来这就是dp题吗,我 t c l tcl tcl)
主要思路:
- 在推这道题的dp方程之前我们先来证明称多次天平和称一次天平其实是等价的,为我们后面做铺垫.我们假设 X 1 < X 2 , Y 1 < Y 2 , 且差值都在 m 之内 X1<X2,Y1<Y2,且差值都在m之内 X1<X2,Y1<Y2,且差值都在m之内,那么我们显然可以通过称两次来得到这四把武器,但是我们也可以这样 ( X 1 + Y 2 ) , ( X 2 + Y 1 ) (X1+Y2),(X2+Y1) (X1+Y2),(X2+Y1),此时我们会发现两者的差值显然也是在m以内的,所以我们就发现我们其实可以称一次来解决这个问题
- 我们分析一下题目之后(
看了一下题解之后)发现我们可以使用 d p [ i ] [ j ] dp[i][j] dp[i][j]来记录前 i i i个武器天平左右两段相差 j j j的武器的总重量,那么显然的对于新枚举到的一把武器,我们有三种可能性,要么不放在天平中,此时我们的 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j],假设我们此时放的位置加大了我们的差值,那么此时我们的 d p [ i ] [ j ] = d p [ i − 1 ] [ a b s ( j − a [ i ] ) ] + a [ i ] dp[i][j]=dp[i-1][abs(j-a[i])]+a[i] dp[i][j]=dp[i−1][abs(j−a[i])]+a[i]也就是将原来的差值继续加大,为什么要加上 a b s abs abs呢,是因为我们也可以加到质量原本较轻的位置,使其比较重的还要重.或者减少了我们的差值,此时 d p [ i ] [ j ] = d p [ i − 1 ] [ j + a [ i ] ] + a [ i ] dp[i][j]=dp[i-1][j+a[i]]+a[i] dp[i][j]=dp[i−1][j+a[i]]+a[i],也就是将我们的差值减少到我们现在的位置 - 最后只要统计一下m以内的最大值即可
下面是具体的代码部分:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n,m;
int a[maxn];
int sum[maxn];int dp[200][100*100+5];
int main() {
n=read();m=read();
for(int i=1;i<=n;i++) {
a[i]=read();
sum[i]=sum[i-1]+a[i];
}
memset(dp,-0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++) {
for(int j=0;j<=sum[i];j++) {
dp[i][j]=dp[i-1][j];
dp[i][j]=max(dp[i][j],dp[i-1][abs(j-a[i])]+a[i]);
dp[i][j]=max(dp[i][j],dp[i-1][j+a[i]]+a[i]);
}
}
int ans=0;
for(int i=0;i<=m;i++) ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}