D. Digits DP

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("
");
    }
}
原文地址:https://www.cnblogs.com/EchoZQN/p/14635195.html