Atcoder Beginner Contest 118D - Match Matching 解题报告

Atcoder Beginner Contest 118D - Match Matching 解题报告

1 题目链接

传送门

2 题目大意

题目:火柴匹配
题目大意:

问恰好 n n n 根火柴可以拼出最大的数是多少。

3 解法分析

十年OI一场空,不用string见祖宗

看到这道题后首先考虑贪心。

诶不对,再看看第一个样例。

这不符合贪心罢?

不考虑贪心了,直接 d p dp dp (恼)。

等等先别急,考虑一下更朴素的方法。

考虑 O ( 2 n ) O(2^n) O(2n) d f s dfs dfs

n ⩽ 1 0 4 n\leqslant10^4 n104,那没事了。还是 d p dp dp 罢。

由样例可知每种数字可以用无数遍。

这不裸完全背包么(狂喜)。

状态: d p i dp_i dpi 表示用 i i i 根火柴棍能获得的最大数。

易知转移方程:

d p i = max ⁡ { cal ⁡ ( d p i − c a i , a i ) , d p i } dp_i=\max\{\operatorname{cal}(dp_{i-c_{a_i}},a_i),dp_i\} dpi=max{cal(dpicai,ai),dpi}

其中 cal ⁡ ( i , j ) \operatorname{cal}(i,j) cal(i,j) 表示向 i i i 中加入数字 j j j

完结撒花。

4 解法总结

完全背包

状态: d p i dp_i dpi 表示用 i i i 根火柴棍能获得的最大数。

转移方程:

d p i = max ⁡ { cal ⁡ ( d p i − c a i , a i ) , d p i } dp_i=\max\{\operatorname{cal}(dp_{i-c_{a_i}},a_i),dp_i\} dpi=max{cal(dpicai,ai),dpi}

其中 cal ⁡ ( i , j ) \operatorname{cal}(i,j) cal(i,j) 表示向 i i i 中加入数字 j j j

5 AC Code

#include <bits/stdc++.h>
using namespace std;

int n, m;
int a[17], c[17] = {0, 2, 5, 5, 4, 5, 6, 3, 7, 6};

struct node {
    int cnt[17], len;
    bool operator > (const node& b) const {
        if (len != b.len)
			return len > b.len;
        for (int i = m; i >= 1; --i)
			if (cnt[i] != b.cnt[i])
				return cnt[i] > b.cnt[i];
        return 0;
    }
}dp[10007];

int main() {
    scanf("%d%d", &n ,&m);
    for (int i = 1; i <= m; ++i)
		scanf("%d", &a[i]);
    sort(a + 1, a + m + 1);
    for (int i = 1; i < n; ++i)
		dp[i].len = -1000007;
    for (int i = m; i >= 1; --i) {
        for (int j = 0; j <= n; ++j) {
            if (c[a[i]] <= j) {
                node t = dp[j - c[a[i]]];
                ++t.cnt[i];
                ++t.len;
                if (t > dp[j])
					dp[j] = t;
            }
        }
    }
    for (int i = m; i >= 1; --i)
		for (int j = 1; j <= dp[n].cnt[i]; ++j)
			putchar(a[i] + '0');
	puts("");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值