题目大意
有 天,每天可购买
个糖,不同时间、不同的糖有不同价格。每天购买
个糖有额外代价
。须保证第
天结束时累计购买数达到
。问最小代价。
题解
写了一个朴素的二维 DP,预先对每一天的糖价格排序,然后设 为第
天结束时买了
个糖的最小代价。则
其中 表示前
天最小的
个糖的价格和。
这么做是 的。当然由于后面整个都是只和
相关的函数,因此应该也可以用单调队列维护,时间复杂度降为
。
#include <bits/stdc++.h> #define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp) #define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp) using namespace std; int read(){ int f = 1, x = 0; char c = getchar(); while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();} while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar(); return f * x; } int n, m, c[305][305], sum[305][305]; int f[305][305]; inline int sqr(int x){ return x * x; } void init(){ n = read(), m = read(); REP(i, 1, n){ REP(j, 1, m) c[i][j] = read(); sort(c[i] + 1, c[i] + m + 1); sum[i][0] = 0; REP(j, 1, m) sum[i][j] = sum[i][j - 1] + c[i][j]; } } void solve(){ memset(f, 0x3f, sizeof(f)); f[0][0] = 0; REP(i, 1, n) REP(j, i, n) REP(k, max(i - 1, j - m), j) f[i][j] = min(f[i][j], f[i - 1][k] + sqr(j - k) + sum[i][j - k]); printf("%d\n", f[n][n]); } int main(){ init(); solve(); return 0; }