Particle

競技プログラミングについての雑記

AOJ 0561: Books

ジャンル毎にx冊売った時の合計金額を前計算しておく。
普通にナップサック問題を解けば、解けます。実際には可能かもしれませんが、1次元配列ではDPできませんでした。

#include <algorithm>
#include <cstdio>
#include <vector>
#include <functional>
using namespace std;

vector<int> books[10];
vector<int> sell[10];
int dp[11][2001];

int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	
	for(int i = 0; i < n; i++){
		int a,b;
		scanf("%d%d",&b,&a);
		books[a-1].push_back(b);
	}
	
	for(int i = 0; i < 10; i++) sort(books[i].begin(),books[i].end(),greater<int>());
	
	for(int i = 0; i < 10; i++){
		sell[i].push_back(0);
		for(int j = 0,j_n = min(k,(int)books[i].size()); j < j_n; j++){
			sell[i].push_back(books[i][j]+sell[i][j]+2*j);
		}
	}
	
	for(int i = 0; i < 10; i++){
		for(int j = 0,j_n = sell[i].size(); j <= k; j++){
			for(int l = 0; l<=k; l++){
				dp[i+1][l] = max(max(dp[i+1][l],dp[i][l]),l>=j&&j<j_n?dp[i][l-j]+sell[i][j]:0);
			}
		}
	}
	
	printf("%d\n",dp[10][k]);
	
	return 0;
}