D. Digits DP
题目大意:
你有 (n) 张卡片,每张卡片上有一个数字,你可以选择一个非空的集合,这些卡片上的数字相乘最后得到的十进制数的个位上的数字是 (d) ,问满足要求的最大的数
题解:
很容易想到的是 (DP) 的定义:(dp[i][j]) 表示前 (i) 个数,个位上的数是 (j) 的最大值。
这个题目的坑点在于如果直接乘起来的话会爆 (long\,long)
所以需要用对数函数转化成加法,然后就只要注意一下这个求路径的方法就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
double dp[maxn][11];
int f[maxn][11],pre[maxn][11];
vector<int>ans;
ll a[maxn];
int main() {
int n, d;
scanf("%d%d", &n, &d);
memset(f,-1,sizeof(f));
f[0][1] = 0;
for(int i=1;i<=n;i++) {
scanf("%lld", &a[i]);
for (int j = 0; j <= 9; j++) {
if (f[i - 1][j] != -1) {
int k = a[i] * j % 10;
double cur = dp[i - 1][j] + log(1.0 * a[i]);
if (cur > dp[i][k]) {
f[i][k] = 1, dp[i][k] = cur, pre[i][k] = j;
}
if (f[i][j] == -1 || dp[i - 1][j] > dp[i][j]) {
dp[i][j] = dp[i - 1][j], f[i][j] = 0, pre[i][j] = j;
}
}
}
}
if(f[n][d]==-1){
printf("-1
");
return 0;
}
int now = n,pos = d;
while(now>=1) {
if (f[now][pos]) {
ans.push_back(a[now]);
pos = pre[now][pos];
}
now--;
}
if(!ans.size()) printf("-1
");
else {
sort(ans.begin(),ans.end());
printf("%d
",ans.size());
for(auto x:ans) printf("%d ",x);
printf("
");
}
}