题目链接

题意:

给出你Codeforces 1510D. Digits(DP+数学+思维)_i++个数,让你任选其中几个数,是的乘积个位为Codeforces 1510D. Digits(DP+数学+思维)_状态转移_02且乘积最大。

思路:

我们看题意中要求的,最大是n个数的乘积,我们没办法直接用long long 来表示,那么我们可以利用数学的转化,将数的乘积转化成数的加也就是
Codeforces 1510D. Digits(DP+数学+思维)_状态转移_03
我们直接可以记录指数即可(用小数)
我们维护出乘积之后,我们再来看个位变成要求的,假设个位要求的是Codeforces 1510D. Digits(DP+数学+思维)_状态转移_04,当前数是52,那他就需要从(2*x)%10=3这个x的状态转移过来。
所以我们就得到了状态转移方程:

int k = j * a[i] % 10;
if(a[i] == 1 || dp[i][k] < dp[i - 1][j] + (double)log2(a[i])) ///a[i]=1是可以直接取的
{
dp[i][k] = dp[i - 1][j] + (double)log2(a[i]); /// 利用2^次方来比较大小
num[i][k] = j;
}

我们用dp来计算指数,实现最大化乘积,用num记录转移过来的位置。

看一下代码吧

int n, m;
double dp[maxn][10];
int num[maxn][10];
int a[maxn];
vector<int> v;
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin>>a[i];
}
memset(num,-1,sizeof num);

for(int i = 0; i < 10; i++) dp[0][i] = -1e9;
dp[0][1] = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < 10; j++) dp[i][j] = dp[i - 1][j];
for(int j = 0; j < 10; j++)
{
int k = j * a[i] % 10;
if(a[i] == 1 || dp[i][k] < dp[i - 1][j] + (double)log2(a[i])) ///a[i]=1是可以直接取的
{
dp[i][k] = dp[i - 1][j] + (double)log2(a[i]); /// 利用2^次方来比较大小
num[i][k] = j;
}
}
}
if(dp[n][m] < 0)
{
puts("-1");
}
else
{
for(int i = n; i ; i--)
{
if(num[i][m] != -1)
{
v.push_back(a[i]), m = num[i][m];
}
}
if(v.size() == 0)
{
puts("-1");
return ;
}
else
{
printf("%d\n", (int)v.size());
for(int i = 0; i < (int)v.size(); i++)
{
ll x = v[i];
printf("%lld ", x);
}
puts("");
}
}
}