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. 问题是,要做多少次变换,使得这个数变成个位