题目链接:点击进入
题目
题意
给你一个长度 n 的数组,让你将他分成几个区间,要求区间内任意两个数之积都不能是平方数( 区间只有一个数也可以 ),让区间数尽可能地小( 不能排序 )
思路
枚举数组,记录区间内此数前面的数中是否有能与它乘积为平方数的数,如果有就以此数为间隔,形成新一个区间。
记录的方法:记录质因子数目的奇偶情况。
一个平方数,他的质因子( 除去 1 )的数目一定是偶数。例如:4 = 2 * 2 ,36 = 2 * 2 * 3 * 3 ;
如果两个数的质因子( 除去 1 )合起来后,数目都是偶数那么这两个数乘积为平方数。
根据这两个性质,我们就可以通过记录 前面数的质因子数目的奇偶情况 来判断这个数前面是否存在与它乘积为平方数的数。
因为质因子数目不止一个,所以我们可以根据数目的奇偶情况进行质因子乘积,只需标记乘积即可。
分解质因子,枚举质数的时候枚举到 5e3 即可,因为 5e3 * 5e3 > 1e7 , 剩下的只能是一个质数,因为如果超过一个,那么就不符合题目数据范围的要求了。
代码
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
int t,n,m,k,p[maxn],a[maxn];
map<int,int>mp;
int prime[N],len;
bool vis[N];
void init()
{
vis[1]=1;
for(int i=2;i<=N;i++)
{
if(!vis[i]) prime[len++]=i;
for(int j=0;j<len&&(ll)prime[j]*i<=N;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
init();
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
int ans=1;
for(int i=1;i<=n;i++)
{
int x=a[i],tmp=1;
for(int j=0;j<len;j++)
{
if(x%prime[j]==0)
{
int sum=0;
while(x%prime[j]==0)
{
x/=prime[j];
sum++;
}
sum%=2;
if(sum)
tmp*=prime[j];
}
}
if(x>1)
tmp*=x;
if(mp[tmp])
{
ans++;
mp.clear();
mp[tmp]++;
}
else mp[tmp]++;
}
cout<<ans<<endl;
mp.clear();
}
return 0;
}