D.Digits

Posted Lnn.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D.Digits相关的知识,希望对你有一定的参考价值。

前言:log防爆orz orz


题目传送门

D.Digits
  题目类型:dp,log防爆。
  解析:对于这种按照某种限制随意取最大值的题,我们考虑dp。以dp[i][j]表示前i个中选一些数,乘积的个位为j的情况下,乘积的最大值。
  现在有一个问题,1e5个数的乘积最大是1000^1e5 = 10^3e5,显然无法存储,由于只有乘法运算,我们可以用log来表示,因为log(a*b) = loga + logb,同时乘积的最大值也变成了log(10^3e5) 约等于 1e6 , 相应的,dp数组要用double类型
  像背包一样,对于每个数,可选可不选
  当不选时,继承上一位,有dp[i][j] = dp[i-1][j]。
  当选定时,先考虑单选i,有dp[i][j] = max(dp[i][j],log(a[i]);
  然后考虑从上一位转移,令nex = j*(a[i]%10)%10。dp[i][nex] = max(dp[i][nex] ,dp[i-1][j] + log(a[i]))。
  再用一个链表结构存储每一个dp的上一个取值状态,用来输出。
  code:

#include <bits\\stdc++.h>

using namespace std;

int n,d,cnt,a[101010],ans[101010],nid[101010][15];
double dp[101010][15];
typedef pair<int,int>pii;
pii last[101010][15];

void init()

    for(int i = 0 ; i <= n ; ++i)
        for(int j = 0 ; j <= 9 ; ++j)
            dp[i][j] = -1e9;


int main()

    ios::sync_with_stdio(false);
    cin >> n >> d ;
    for(int i = 1 ; i <= n ; ++i)
        cin >> a[i] ;
    init();
    for(int i = 1 ; i <= n ; ++i)
        double x = log2(a[i]);
        for(int j = 0 ; j <= 9 ; ++j)
            dp[i][j] = dp[i-1][j];
            last[i][j] = last[i-1][j];
            nid[i][j] = nid[i-1][j];
        
        for(int j = 0 ; j <= 9 ; ++j)
            if(a[i]%10 == j)
                if(dp[i][j] < x)
                    dp[i][j] = x;
                    last[i][j] = 0,0;
                    nid[i][j] = i;
                
            
            if(dp[i-1][j] != -1e9)
                int nex = j*(a[i]%10)%10;
                if(dp[i][nex] <= dp[i-1][j] + x)
                    dp[i][nex] = dp[i-1][j] + x;
                    last[i][nex] = nid[i-1][j] , j;
                    nid[i][nex] = i;
                
            
        
    
    int i = n , now = d;
    while(nid[i][now])
        ans[++cnt] = nid[i][now];
        int j = last[i][now].first , k = last[i][now].second;
        i = j , now = k;
    
    if(!cnt)cout << -1 << endl ;
    else 
        cout << cnt << endl ;
        for(int i = 1 ; i <= cnt ; ++i)
            cout << a[ans[i]] << " " ;
        cout << endl ;
    
    return 0;


以上是关于D.Digits的主要内容,如果未能解决你的问题,请参考以下文章

阿尔法乘积

牛牛想对一个数做若干次变换,直到这个数只剩下一位数字。 变换的规则是:将这个数变成 所有位数上的数字的乘积。比如285经过一次变换后转化成2*8*5=80. 问题是,要做多少次变换,使得这个数变成个位

算法训练 阿尔法乘积

算法训练 阿尔法乘积

两位数相乘的口算方法

子序列权值乘积(数论)