题目大意:
给出两个序列,询问是否存在一种选下标的方案使得:
也就说a和b要么一起拿要么一起不拿
题目思路:
因为状态被绑定,所以可以直接考虑他们绑在一起
假设:
那么必然有:
所以说可以让b序列每个数都,之后令
也就说问题转换为了,求取的物品重量为0时,最大权值
这样就可以直接01背包了。
考虑到出现负数的情况,整体增加一个偏移量即可
Code:
/*** keep hungry and calm CoolGuang! ***/ //#pragma GCC optimize(3) #include <bits/stdc++.h> #include<stdio.h> #include<queue> #include<algorithm> #include<string.h> #include<iostream> #define debug(x) cout<<#x<<":"<<x<<endl; #define dl(x) printf("%lld\n",x); #define di(x) printf("%d\n",x); typedef long long ll; typedef unsigned long long ull; using namespace std; const ll INF= 1e18+7; const ll maxn = 2e5+700; const int M = 1e6+8; const ll mod= 1e9+7; const double eps = 1e-9; const double PI = acos(-1); template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;} ll n,m,p; int dp[105][maxn]; int a[maxn],b[maxn]; ll base = 10000; int main(){ read(n);read(m); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=n;i++){ read(b[i]); b[i] *= m; } memset(dp,-1,sizeof(dp)); dp[0][base] = 0; for(int i=1;i<=n;i++){ for(int k=0;k<=3*base;k++) dp[i][k] = dp[i-1][k]; int w = b[i] - a[i]; for(int k=w;k<=3*base;k++) if(~dp[i-1][k-w]) dp[i][k] = max(dp[i-1][k-w]+a[i],dp[i][k]); } di(dp[n][base]==0?-1:dp[n][base]); return 0; }