AtCoder Beginner Contest 192 F - Potion

GsjzTle發表於2021-02-21

題目連結

點我跳轉

題目大意

給定 \(N\) 個物品和一個 \(X\) ,第 \(i\) 個物品的重量為 \(ai\),你可以從中選擇任意個物品(不能不選)

假定選擇了 \(S\) 個物品,物品的總重量為 \(V\)

那麼再滿足 \((X - V) \% S = 0\) 的前提下還需要支付 \((X - V) / S\)\(money\)

問最少需要支付多少 \(money\)

解題思路

\(S\) 一定時

  • 為滿足 \((X - V) \% S = 0\),則 \(V\) 需滿足 \(V = X \% S\)

  • 為了使支付的 \(money\) 最少, 則 \(V\) 要儘可能大

於是可以列舉 \(S\)

並定義 \(dp[i][j][k]\) 表示從前 \(i\) 個物品中選擇了 \(j\) 個物品使得總重量最大,且這 \(j\) 個物品的總重量 \(\% S = k\)

那麼對於每個物品只有兩種狀態 : 選 \(or\) 不選

於是不難得到 :

\(dp[i][j][k] = dp[i - 1][j][k]\)

\(dp[i][j][k] = dp[i - 1][j - 1][(k - a[i] % S + S) % S] + a[i]\)

最後取最小的 \((X - dp[N][S][X \% S]) / S\) 即可

AC_Code

#include<bits/stdc++.h>

#define rep(i , a , b) for(int i = a ; i <= b ; i ++)

#define int long long

using namespace std;

const int N = 1e2 + 10;

int a[N] , dp[N][N][N];

signed main()
{
	int n , x , mi = 1e18;
	
	cin >> n >> x;

	rep(i , 1 , n) cin >> a[i];
	
	rep(S , 1 , n)
	{
		memset(dp , -1 , sizeof(dp));
		
		dp[0][0][0] = 0;
		
		rep(i , 1 , n) rep(j , 0 , S) rep(k , 0 , S - 1)
		{
			dp[i][j][k] = dp[i - 1][j][k];
				
			if(j > 0 && ~dp[i - 1][j - 1][(k - a[i] % S + S) % S]) 
			
			dp[i][j][k] = max(dp[i][j][k] , dp[i - 1][j - 1][(k - a[i] % S + S) % S] + a[i]);
			
		}
		
		int res = dp[n][S][x % S];
		
		if(~res) mi = min(mi , (x - dp[n][S][x % S]) / S);
	}
	
	cout << mi << '\n';
	
	return 0;
}