Codeforces Round #694 (Div. 2) D.Strange Definition

传送门:https://codeforces.com/contest/1471/problem/D
一、题意:
在一组长度为n的数组中,如果存在a[i],a[j]满足lcm(a[i],a[j])/gcd(a[i],a[j]) 为一个完美开方数,则称a[i]与a[j]为相邻数(j可以等于i)。
di为与a[i]为相邻数的数字个数,每秒钟会将同类的相邻数相乘并代替原数字。
如20,5,80为一组相邻数,一秒后就变为8000,8000,8000。
接下来有q次询问,每次输入一个w,问w秒后d的最大值。
二、思路:
1.lcm(x,y)=xy/gcd(x,y)
2.lcm(x,y)/gcd(x,y)=xy/gcd(x,y)2
容易看出当xy为完美开方数时能够符合条件。
可以将x和y分解为自身的质因数的平方相乘,分解到最后如果x==y则xy为同类,详情见代码

		for (int i = 1; i <= n; i++) {
			scanf("%d", &x);
			for (int j = 2; j*j <= x; j++)
				while (x % (j*j) == 0)x /= (j*j);
			m[x]++//(记录同类数的个数);
		}

0秒时最大值就是记录下来的同类数个数,1秒之后则不变。
因为当m[x]为奇数时,说明该类有奇数个元素,相乘之后类型依然不变。
如20,45,80通过上述步骤分解后为都变为5,相乘之后为72000,72000分解后依然是5。
当m[x]为偶数时,相乘之后类型发生改变。
如20,45,80,125分解后变为5,相乘之后为9000000,分解后为1。
所以在一秒之后,类型都不再发生改变。所以在第一次统计之后,将m[x]为偶数的个数与m[1]合并,奇数不变,再次统计个数,详情见代码

	int ans1 = 0,ans2=0,ansodd=0;
		for (auto e : m) {
			ans1 = max(ans1, e.second);//统计0秒时的最大值
			if (e.second & 1) { ansodd = max(ansodd, e.second); }//如果为奇数个,用ansodd统计最大值
			else ans2 +=e.second;//如果是偶数,将其合并为同类
		}
		if (m[1]&1)ans2 += m[1];//将还未合并1类的合并
		ans2 = max(ans2, ansodd);

完整代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define ll long long 
using namespace std;
const int inf = 1e9 + 7;
map<int, int>m;
int main()
{
	int t;
	scanf("%d", &t);
	while (t--) {
		m.clear();
		int n;
		scanf("%d", &n);
		int x;
		for (int i = 1; i <= n; i++) {
			scanf("%d", &x);
			for (int j = 2; j*j <= x; j++)
				while (x % (j*j) == 0)x /= (j*j);
			m[x]++;
		}
		int ans1 = 0,ans2=0,ansodd=0;
		for (auto e : m) {
			ans1 = max(ans1, e.second);//统计0秒时的最大值
			if (e.second & 1) { ansodd = max(ansodd, e.second); }//如果为奇数个,用ansodd统计最大值
			else ans2 +=e.second;//如果是偶数,将其合并为同类
		}
		if (m[1]&1)ans2 += m[1];//将还未合并1类的合并
		ans2 = max(ans2, ansodd);
		ll q, w;
		scanf("%lld", &q);
		while (q--) {
			scanf("%lld", &w);
			if (w)printf("%d\n", ans2);
			else
				printf("%d\n", ans1);
		}
	}
	return 0;
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值