Codeforces Round #480 (Div. 2) D. Perfect Groups

cf 980D(题目链接)

题记

大二到大三小学期(其实是暑假了,但是因为这一系列周赛开始于小学期,就用小学期称呼它了)第三次排位赛I题。这次周赛爆零了,整个过程非常的困难,并不是自暴自弃式爆零,而是因为是俱乐部内部排位赛,总共五场排位赛,前两场都不好,想着这一场一定要跟上,这个执念对我影响很大,一度让我心态非常焦虑和着急,看着榜上过题,坐在身边的同学有代码可敲,我在思路上挂机,就越发着急,结果就是越着急越没有思路吧,不能沉下心来好好想某一道题。

这道题是我补题的第一顺位,因为陈朝潮学长打完跟我说这是个签到题。

签到个鬼,1800到2500的题集区间,这个玩意儿2100分。虽然补了,但是想想当时排位赛场的话我是没有可能做出来的。比如这个基础筛法就只看过方法从来没有在题目上写过。

但是既然补掉了,下次就心里有数了。

题意

对于一个数组,希望把其中的元素分成尽量少的若干个组,使得每个组中,任意两个元素之积为完全平方数。设这个分成的组的数量为k,现在给出一个长度为n的数组a,求出对于 1 <= k <= n的每一个k值,对应k为答案的a数组的连续子序列的数量。

思路

参考博客

官方题解(更推荐)

在思考这个问题的时候,最核心的一点是,我们对给定数组元素进行如上分组时,采取什么策略才可以使得组数最少?不妨尝试依次考虑每一个元素,不断将未分组的元素添加到已分组的集合中。现在来看当前待分组的元素,我们首先会想到是不是能够把它添加到之前的某一个组中去?如果能,我们来考虑这个可以添加进的组和这个元素有什么共性。假设组中有元素x,待分组的元素为y,那么x * y是一个完全平方数。完全平方数意味着,分解质因数之后,这个数的每一个因子出现的频率都为偶数。那么我们把x,y分别分解质因数,去除各自因数中成对的因子,剩下的因子仍可以和另一个数中的因子凑成一对。比如:

若x为40,则x = 2 * 2 * 2 * 5,取出成对因子后,x = 2 * 5。现在要有一个y和x相乘后仍为完全平方数,那么显然y中必然需要有2,5两个因子。除此之外,y中只能再出现成对的质因子。比如y = 2 * 5 * 7 * 7就可以和x构成完全平方数,而y = 2 * 5 * 5就不可以。

这样事情就很清楚了,去除成对的质因子后,剩下的因子完全相同,即剩下的数完全相等的两个数才能分为一组。当然,0是一个例外,可以任意分为一组。

于是思路就有了:将所有数取出完全平方因子,一个区间中有多少不同的数,这个区间就需要分成几组。而计算答案的时候,只需要枚举区间的左端点,推进区间右端点来枚举每个区间,记录每个数前一个和它相同数的位置,就可以统计答案。这一点可以见参考博客。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int max_n = 5e3 + 50;
int n;
vector<int> pri; //保存素数
int the_before[max_n];
int ans[max_n];
int a[max_n];

int del_per(int x) {
	if (x == 0)
		return x;
	//用每一个素数去试探着去掉完全平方
	for (int i = 0; i < (int)pri.size(); i++) {
		int divi = pri[i] * pri[i];
		while(x % divi == 0)
			x /= divi;
	}
	return x;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}

	//对a[i]进行去完全平方数化
	{
		//筛出素数
		bool notp[10001];
		memset(notp, false, sizeof(notp));
		for (int i = 2; i <= 10000; i++) {
			if(notp[i])
				continue;
			pri.push_back(i);
			for (int j = i << 1; j <= 10000; j += i) {
				notp[j] = true;
			}
		}
		// cout << "素数筛完成" << endl;
		//对每一个a[i]去掉完全平方
		// cout << "去平方之后:" << endl;
		for (int i = 1; i <= n; i++) {
			a[i] = del_per(a[i]);
			// printf("%d: %d\n", i, a[i]);
		}
	}

	//记录对于每一个a[i]离它最近的前一个和它值相同的位置
	map<int, int> pos;
	for (int i = 1; i <= n; i++) {
		the_before[i] = pos[a[i]]; 
		// printf("the_before[%d]:%d\n", i, the_before[i]);
		//如果之前没有的话,这个值就是0,就会比左区间小,含义上来说可以完成答案的统计工作
		pos[a[i]] = i;
	}
	// cout << "记录对于每一个a[i]离它最近的前一个和它值相同的位置" << endl;

	//扫描每一个连续区间,对该区间最小可以进行的分组cnt,统计到答案中
	for (int i = 1; i <= n; i++) {
		int cnt = 0;
		for (int j = i; j <= n; j++) {
			if(a[j] != 0 && the_before[j] < i) //写错成过the_before[a[j]],数组的含义要搞清楚啊
				cnt++;
			// if(cnt == 0) 
			// 	cnt++; //这种写法是错误的,如果首位是0,第二位是1,答案应该是1,这么写会变成2
			ans[max(1, cnt)]++;
		}
	}
	for (int i = 1; i <= n; i++) {
		printf("%d", ans[i]);
		if(i != n) printf(" ");
		else printf("\n");
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值