Cod sursa(job #502553)

Utilizator pauldbPaul-Dan Baltescu pauldb Data 20 noiembrie 2010 00:34:51
Problema Ghiozdan Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.59 kb
#include <cstdio>
#include <vector>
#include <deque>

using namespace std;

const int MAX_WEIGHT = 210;
const int MAX_CAPACITY = 75010;
const int INFINITY = 100000;

int totalCapacity, maxCapacity;
int weightsCount[MAX_WEIGHT];
int dp[2][MAX_CAPACITY];
vector <int> solution;

void read() {
	freopen("ghiozdan.in", "r", stdin);

	int noObjects;
	scanf("%d %d", &noObjects, &totalCapacity);

	for (int i = 1; i <= noObjects; ++i) {
		int weight;
		scanf("%d", &weight);
		++weightsCount[weight];
	}
}

void doDP(int minWeight, int maxWeight, int desiredWeight) {
	int now = minWeight&1, last = now^1;

	dp[last][0] = 0;
	for (int i = 1; i <= desiredWeight; ++i)
		dp[last][i] = INFINITY;

	for (int i = minWeight; i <= maxWeight; ++i, now ^=1, last ^= 1)
		for (int j = 0; j < i; ++j) {
			deque <int> prevLine;
			for (int k = j; k <= desiredWeight; k += i) {
				while (prevLine.size() > 0 && dp[last][prevLine.back()]
						+ (k-prevLine.back()) / i >= dp[last][k])
					prevLine.pop_back();
				prevLine.push_back(k);

				while (prevLine.front() < k-i*weightsCount[i])
					prevLine.pop_front();

				dp[now][k] = dp[last][prevLine.front()] + (k-prevLine.front()) / i;
			}
		}
}

void findSolution(int minWeight, int maxWeight, int desiredWeight,
		int noObjects) {
	if (minWeight == maxWeight) {
		for (int i = minWeight; i <= desiredWeight; i += minWeight)
			solution.push_back(minWeight);
	} else {
		int middleWeight = (minWeight+maxWeight) / 2;

		doDP(minWeight, middleWeight, desiredWeight);

		int tmp[MAX_CAPACITY];
		for (int i = 0; i <= desiredWeight; ++i)
			tmp[i] = dp[middleWeight&1][i];

		doDP(middleWeight+1, maxWeight, desiredWeight);

		for (int weightLeft = 0; weightLeft <= desiredWeight; ++weightLeft) {
			int weightRight = desiredWeight - weightLeft;
			int noObjectsLeft = tmp[weightLeft];
			int noObjectsRight = dp[maxWeight&1][weightRight];

			if (noObjectsLeft + noObjectsRight == noObjects) {
				if (weightLeft > 0) 
					findSolution(minWeight, middleWeight, weightLeft, noObjectsLeft);
				if (weightRight > 0) 
					findSolution(middleWeight+1, maxWeight, weightRight, noObjectsRight);
				break;
			}
		}
	}
}

void solve() {
	doDP(1, MAX_WEIGHT-1, totalCapacity);

	maxCapacity = totalCapacity; 
	while (dp[(MAX_WEIGHT-1)&1][maxCapacity] == INFINITY && maxCapacity >= 0)
		--maxCapacity;

	findSolution(1, MAX_WEIGHT-1, maxCapacity, dp[(MAX_WEIGHT-1)&1][maxCapacity]);
}

void write() {
	freopen("ghiozdan.out", "w", stdout);

	printf("%d %d\n", maxCapacity, solution.size());
	for (size_t i = 0; i < solution.size(); ++i)
		printf("%d\n", solution[i]);
}

int main() {
	read();
	solve();
	write();
	return 0;
}