Atcoder abc_257 E Addition and Multiplication 2

Atcoder abc_257 E Addition and Multiplication 2

本篇质量较水请谨慎阅读。

题目大意

初始时, x = 0 x=0 x=0

n n n元钱,你可以花 c i ( 1 ≤ i ≤ 9 ) c_i(1\leq i\leq9) ci(1i9)元将 x = x ∗ 10 + i x=x*10+i x=x10+i。求 x x x最大多少。

思路

前情提要

考试最后30分钟,一开始排除动态规划想到贪心,10分钟兜兜转转又回到动态规划???

不过还好5分钟就想出了正解。

不扯了,下面是正经的。

有10个物品,把 c i c_i ci看成物品重量, n n n看成背包体积, i i i作为物品价值 ( 1 ≤ i ≤ 9 ) (1\leq i \leq 9) (1i9)

是不是有了背包的感觉。

d p [ i ] dp[i] dp[i]表示剩余 i i i容量时的最大值。

由于我们的数字可能十分大,属于 long long 见了都落泪,int 看了直下跪。让我们来分析一下。

本题其实本质是在一定条件下选若干数字,使他们的放在一起最大。根据小学奥数,我们知道要把较大的数字放大前面来使数字最大。 so ,我们其实只要存下每个状态的每个数字有多少个就可以了。

那我们在比较大小的时候,先比较位数,再从大到小比较每个数字的数量。

我们的动态转移方程就是:
d p [ i ] = m a x ( d p [ i ] , d p [ i + c k ] + k ) dp[i]=max(dp[i],dp[i+c_k]+k) dp[i]=max(dp[i],dp[i+ck]+k)
其中 + k +k +k为添加一个数字 k k k

我们的 d p [ i ] dp[i] dp[i]用结构体会好打很多,在代码中 d p [ i ] . c i s [ j ] dp[i].cis[j] dp[i].cis[j]表示 d p [ i ] dp[i] dp[i]状态下数字 j j j有多少个。

CODE

#include
using namespace std;

#define ll long long

const ll maxn=2e6+5;

struct node
{
    ll m=0;
    ll cis[11]={0};//第几个数字有多少个
}dp[maxn];

ll n;
ll vis[15];//c_i

ll cmp(node a,node b)//比较,a>b返回1,a
{
        if(a.m>b.m) return 1;
        else if(a.m<b.m) return -1;//比较位数
    for(ll i=9;i>=1;i--)
    {
        if(a.cis[i]>b.cis[i]) return 1;//比较哪一个数字多,多的直接比另外一个大
        else if(b.cis[i]>a.cis[i]) return -1;
    }
    return 0;
}

int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=9;i++) scanf("%lld",&vis[i]);
    for(ll i=1;i<=9;i++)
    {
        for(ll j=n-vis[i];j>=0;j--)
        {
            node tmp=dp[j+vis[i]];
            tmp.m++;//增加1个数字,位数++
            tmp.cis[i]++;//对应的数字个数++
            if(cmp(dp[j],tmp)==-1)//tmp>dp[j]
                dp[j]=tmp;
        }
    }//背包
    for(ll i=9;i>=1;i--)
    {
        for(ll j=dp[0].cis[i];j>=1;j--) printf("%lld",i);//输出
    }
}

ps:忘记判断位数,考试没了88分…… 惨寄。

你可能感兴趣的:(atcoder题解,算法,动态规划,c++)