https://codeforces.com/contest/1132/problem/E

大意比较简单,说一下吧:

8个物品,权依次为1~8,第i个物品有cnt[i]([0,1e16])个

给定一个n([1,1e18]),

从物品中取出若干个,可使得取出物品的总权值为sum,求在sum<=n的条件下,sum的最大值

 

题解用的技巧很巧妙,取1~8的LCM为L

那么sum可以化为AL+B

对于物品i,可以分为2部分,

一部分从中取出 qi个(qi<=L/i),那么这部分的总权值小于L

另一部分按照 L/i  个为1捆,分成若干(pi)/捆,我们从中取出的捆数就是[0,pi]

当q[i]从0到L/i-1遍历时,对于物品i就经历了所有的情况

 

具体的:

我们为每个i确定一个q[i],那么对于某一种情况,我们记录下它的所有物品的p[i]的和,那么

这种情况就可以得到sumq[i]+L*[0,sump[i]]的权值和,这种情况就可以很方便的计算sum最大值了

当然了,不能暴力所有情况,要加一层DP,用dp[i][j]记录使用前n个物品sumq[i]时的sump[i]

,这样复杂度就是 8*(L*8)*,最大就4e7左右吧,其实复杂度有点险,但还是能过

 

最后贴个代码

#define CLR(a) memset((a),0,sizeof(a))
#define RE(i,a) for(int i=0;i<(int)a;++i)
#define RE2(i,a) for(int i=1;i<=(int)a;++i)
#define F2(i,a,b) for(int i=a;i>=b;--i)
#define F(i,a,b) for(int i=a;i<=b;++i)
#define PB push_back
#define PII pair<int,int>
#define x first
#define y second
/////////////////////////////////////////////////
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int maxn = int(9);
const int L = 840;
ll n;
ll cnt[9];
ll dp[maxn][9 * L];
int main()
{
	//	freopen("C:\\Users\\VULCAN\\Desktop\\data.in","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T(1), cas(0);
	while (++cas, T--)
	{
		cin >> n; RE2(i, 8)cin >> cnt[i];
		memset(dp, -1, sizeof(dp));
		dp[0][0] = 0;
		RE2(i, 8)
		{
			RE(j, 8 * L+1)
			{
				int up = min(1ll * L / i, cnt[i]);
				F(k,0,up)
				{
					if (j - i * k < 0)break;//非法
					if (dp[i - 1][j - i * k] == -1)continue;
					ll &ret = dp[i][j];
					ret = max(ret, dp[i - 1][j - i * k] + (cnt[i] - k) / (L / i));
				}
			}
		}
		ll ans(0);
		RE2(j, 8 * L)if (j <= n && ~dp[8][j])
		{
			ll res = n - j;
			ll fil = min(dp[8][j] * L, res / L * L);
			ans = max(ans, fil + j);
		}
		cout << ans << endl;
	}
	return 0;
}