题目链接:https://codeforces.com/problemset/problem/980/D
题意: 对于一个数组,我们定义它的一种属性为: 将数组中的元素最少需要分成多少组使得每一组中的任意两个元素的乘积都是完全平方数. 然后给你一个长度为n的数组(n <= 5000), 问对于n的所有的连续的子数组里有多少个的属性为1、2、3......n。元素的值域为(-1e8<=ai<=1e8).
思路: 数组长度很小,n^2复杂度可过. 我们发现如果两个数a b 的乘积为平方数,既a*b = x^2, 且b*c = y^2,
则a*b*b*c = x^2*y^2,有 a*c = x^2*y^2/(b^2) 所以a b c 可分在一组,于是我们就可以通过n^2来将处理数组元素将其分类,再n^2处理出各个区间里的种类.
WA点: 注意0的特殊性.
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e3+10;
ll a[maxn];
int kind[maxn], ans[maxn], vis[maxn];
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%lld", a+i);
memset(kind, -1, sizeof kind);
int ma = 0;
for(int i = 0; i < n; i++) {
if(a[i] == 0) {
kind[i] = 0;
continue;
}
if(kind[i] == -1) kind[i] = ++ma;
for(int j = i+1; j < n; j++) {
if(a[i]*a[j] < 0) continue;
ll tmp = sqrt(a[i]*a[j]);
if(tmp*tmp == a[i]*a[j]) kind[j] = kind[i];
}
}
memset(vis, -1, sizeof vis);
for(int i = 0; i < n; i++) {
bool zero = false;
int num = 0;
for(int j = i; j < n; j++) {
if(vis[kind[j]] != i) {
vis[kind[j]] = i;
num++;
}
if(a[j] == 0) zero = true;
if(!zero) ans[num]++;
else if(num == 1) ans[1]++;
else ans[num-1]++;
}
}
for(int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
return 0;
}