不得不说区域赛的题目,考察的确实是综合能力
这个题开始没想到log的方法,就去想循环节暴搜了。但是循环节暴搜有一个问题就是,每次找到方案后都要重新计算一次乘积,毕竟是暴搜,能找到很多可行方案,TLE了。
如果不用log将乘法转换为加法,这题是没法dp的,因此重要的处理前提就是想到取log。
不得不说,如果是求使用的数的个数最多,循环节暴搜还是很好的。但是这题求的是乘积的最大值,这就搞不了了。
题意:给你一堆数,问你用哪些数能乘起来能得到最大的,个位是d的数。
思路:DP, f[i][j]表示当前选到第i个数,个位数是j的乘积的最大值,此时已经转化为log的和的最大值了。
代码如下
struct node{
bool use; //表示当前这个数有没有被使用
int x, y; //当前数是从 f[x][y]转移过来的
};
double f[N][10];
node pre[N][10];
double lg[N];
int a[N], n, d;
int main()
{
IOS;
cin >> n >> d;
for(int i = 1 ; i <= n ; i ++)
{
cin >> a[i];
lg[i] = log(a[i]);
}
for(int i = 1 ; i <= n ; i ++)
{
int c = a[i] % 10;
f[i][c] = lg[i];
pre[i][c] = {true, i, c}; //自己单独当然可以
for(int j = 0 ; j < 10 ; j ++)
{
if(f[i][j] < f[i - 1][j]) //不选当前这个数
{
f[i][j] = f[i - 1][j];
pre[i][j] = {false, i - 1, j};
}
for(int k = 0 ; k < 10 ; k ++) //选当前这个数
{
if(k * c % 10 == j && f[i - 1][k])
{
if(f[i][j] < f[i - 1][k] + lg[i])
{
f[i][j] = f[i - 1][k] + lg[i];
pre[i][j] = {true, i - 1, k};
}
}
}
}
}
double maxd = 0;
int idx = 0;
for(int i = 1 ; i <= n ; i ++)
if(maxd < f[i][d])
{
maxd = f[i][d];
idx = i;
}
if(!maxd)
{
cout << -1;
return 0;
}
vector<int> ans;
auto t = pre[idx][d];
if(t.use) ans.push_back(a[idx]);
while(t.x != idx)
{
idx = t.x;
d = t.y;
t = pre[t.x][t.y];
if(t.use) ans.push_back(a[idx]);
if(t.x == idx) break;
}
cout << ans.size() << endl;
for(auto x : ans) cout << x << " ";
return 0;
}
原文:https://www.cnblogs.com/luoyicong/p/14619021.html