NC14526 购物(DP)

题目链接

题意:
共 n 天 , 每 天 有 m 种 糖 果 可 以 买 , 也 可 以 不 买 共n天,每天有m种糖果可以买, 也可以不买 nm
价 钱 是 c i j 价钱是c_{ij} cij
每 天 买 k 个 糖 果 需 要 额 外 支 付 k 2 的 钱 每天买k个糖果需要额外支付k^2的钱 kk2
要 每 天 都 能 有 一 个 糖 果 吃 要每天都能有一个糖果吃
问 最 少 花 多 少 钱 每 天 都 能 有 糖 果 吃 问最少花多少钱每天都能有糖果吃
题解:
n , m < = 300 n,m<=300 n,m<=300
最 优 解 , 并 且 没 有 策 略 进 行 贪 心 最优解,并且没有策略进行贪心
那 么 考 虑 d p 那么考虑dp dp
d p [ i ] [ j ] 第 i 天 已 经 有 j 个 糖 果 的 最 小 花 费 dp[i][j]第i天已经有j个糖果的最小花费 dp[i][j]ij
对 于 每 一 天 肯 定 优 先 买 最 便 宜 的 几 个 糖 果 对于每一天肯定优先买最便宜的几个糖果 便
那 么 对 这 一 天 的 糖 果 排 序 , 并 且 求 出 前 缀 和 那么对这一天的糖果排序,并且求出前缀和
然 后 开 始 枚 举 每 一 天 枚 举 总 共 买 糖 果 的 数 量 和 当 天 购 买 糖 果 的 数 量 然后开始枚举每一天枚举总共买糖果的数量和当天购买糖果的数量
进 行 转 移 即 可 进行转移即可
最 后 d p [ n ] [ n ] 为 最 终 答 案 最后dp[n][n]为最终答案 dp[n][n]
AC代码

/*
    Author : zzugzx
    Lang : C++
    Blog : blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
#define mem(a, b) memset(a, b, sizeof(a))

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod = 1e9 + 7;
//const int mod = 998244353;

const double eps = 1e-6;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
const int N = 3e2 + 5;
const ll inf = 0x3f3f3f3f;
const int dir[][2]={{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

int a[N][N], dp[N][N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
//  freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n; i++)
        sort(a[i] + 1, a[i] + 1 + m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            a[i][j] += a[i][j - 1];
    mem(dp, inf);
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= min(n, i * m); j++)
            for (int k = i - 1; k <= min(n, min(j, (i - 1) * m)); k++)
                dp[i][j] = min(dp[i][j], dp[i - 1][k] + a[i][j - k] + (j - k) *(j - k));
    cout << dp[n][n];
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值