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;
}

Guess you like

Origin blog.csdn.net/m0_45699242/article/details/119756735