Cod sursa(job #3269999)

Utilizator MihaiZ777MihaiZ MihaiZ777 Data 21 ianuarie 2025 18:43:27
Problema Problema rucsacului Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.1 kb
#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <cmath>
#include <limits.h>
#include <iostream>
using namespace std;

#define MAXN 5005;
#define MAXW 1000016
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
	
template<typename T> void maximize(T &res, const T &val) { if (res < val) res = val; }
template<typename T> void minimize(T &res, const T &val) { if (res > val) res = val; }

ifstream fin("rucsac.in");
ofstream fout("rucsac.out");
	
long long n, w, val;
long long c[MAXW], v[MAXW];
long long f[MAXW];
long long f2[MAXW];
long long auxv[MAXW];
vector<int> selected;

void ReadData() {
	fin >> n >> w;
	for (int i = 1; i <= n; ++i) {
		fin >> c[i] >> v[i];
	}
}

namespace weights {

int calc(long long *f, int l = 1, int r = n)
{
	long long upper = 0;
	for (int i = l; i <= r; ++i)
		upper += c[i];
	
	minimize(upper, (long long)w);
	for (int s = 0; s <= upper; ++s)
		f[s] = 0;
	
	for (int i = l; i <= r; ++i)
		for (int s = upper; s >= c[i]; --s)
			maximize(f[s], f[s - c[i]] + v[i]);
	
	return upper;
}
	
void trace(int s = w, int l = 1, int r = n)
{
	if (l == r)
	{
		if (s == c[l])
		{
			selected.push_back(l);
		}
	
		return ;
	}
	
	int m = (l + r) >> 1;
	int sleft  = calc(f, l, m + 0);
	int sright = calc(f2, m + 1, r);
	
	long long mx = -1;
	int pleft = 0;
	int pright = s;
	for (int v = max(0, s - sright); v <= min(s, sleft); ++v)
	{
		if (mx < f[v] + f2[s - v])
		{
			mx = f[v] + f2[s - v];
			pleft = v;
			pright = s - v;
		}
	}
	
	trace(pleft , l, m + 0);
	trace(pright, m + 1, r);
}

void solve() {
	weights::calc(f);
	long long res = f[w];
	int weight_used = max_element(f, f + w + 1) - f;
	
	weights::trace(weight_used);	
	fout << res << '\n';
	for (int p : selected) {
	    fout << c[p] << ' ' << v[p] << '\n';
	}
}

} // namespace weights

namespace values {

int calc(long long *values, long long *f, int l = 1, int r = n)
{
	f[0] = 0;
	for (int s = val; s >= 1; --s)
		f[s] = +LLINF;

	for (int i = l; i <= r; ++i)
		for (int s = val; s >= values[i]; --s)
			minimize(f[s], f[s - values[i]] + c[i]);
	
	return val;
}

void trace(long long *values, int s = MAXW, int l = 1, int r = n)
{
	if (l == r)
	{
		if (s == values[l])
		{
			selected.push_back(l);
		}	

		return ;
	}

	int m = (l + r) >> 1;
	int sleft  = calc(values, f, l, m + 0);
	int sright = calc(values, f2, m + 1, r);

	int mn = +INF;
	int pleft = 0;
	int pright = s;
	for (int v = max(0, s - sright); v <= min(s, sleft); ++v)
	{
		if (mn > f[v] + f2[s - v])
		{
			mn = f[v] + f2[s - v];
			pleft = v;
			pright = s - v;
		}
	}

	trace(values, pleft , l, m + 0);
	trace(values, pright, m + 1, r);
}

void solve() {
	int res = calc(v, f);
	while (f[res] > w) --res;
	trace(v, res);
	
	int ans = 0;
	for (int p : selected)
		ans += v[p];

	fout << ans << '\n';
	for (int p : selected)
	{
		fout << c[p] << ' ' << v[p] << '\n';
	}
}

} // namespace values

namespace fptas {

double invlerp(long long a, long long b, long long v) {
  return (double)(v - a) / (b - a);
}

void compress(double eps) {
	long long maxProfit = 0;
	for (int i = 1; i <= n; i++) {
		maxProfit = max(maxProfit, v[i]);
	}
	double scalingFactor = eps * maxProfit / n;
	for (int i = 1; i <= n; i++) {
		auxv[i] = v[i] / scalingFactor;
	}
}
void solve() {
	compress(invlerp(MAXW - 5, LLONG_MAX, val) / 1.5);

	for (int i = 1; i <= n; ++i)
		val += auxv[i];

	int res = values::calc(auxv, f);
	while (f[res] > w) --res;
	values::trace(auxv, res);
	
	int ans = 0;
	for (int p : selected)
		ans += v[p];

	fout << ans << '\n';
	for (int p : selected)
	{
		fout << c[p] << ' ' << v[p] << '\n';
	}
}

} // namespace brute
		
int main()
{
	ReadData();
	if (w <= MAXW - 5) {
		weights::solve();
	} else {
			for (int i = 1; i <= n; ++i) {
			long long term = v[i] * (c[i] <= w);
			if (val + term < 0) {
				val = LLONG_MAX;
				fptas::solve();
			}
			val += term;
		}
		if (val <= MAXW - 5) {
			values::solve();
		}
		else {
			fptas::solve();
		}
	}
	return 0;
}