首页 > 其他 > 详细

D. Digits 区域赛原题

时间:2021-04-05 21:17:20      阅读:17      评论:0      收藏:0      [点我收藏+]

原题链接https://codeforces.com/contest/1510/problem/D

不得不说区域赛的题目,考察的确实是综合能力
这个题开始没想到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;
}

D. Digits 区域赛原题

原文:https://www.cnblogs.com/luoyicong/p/14619021.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!