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(1≤i≤9)元将 x = x ∗ 10 + i x=x*10+i x=x∗10+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) (1≤i≤9)。
是不是有了背包的感觉。
设 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<bits/stdc++.h>
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<b返回-1,a=b返回0
{
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分…… 惨寄。