题意:
有这样一个问题,给出一个数组,把里面的数字分组,使得每一个组里面的数两两相乘都是完全平方数。
问最少可以分成的组数k是多少。
现在一个人有一个数组,他想知道这个数组的连续子数组中,使得上面的问题答案分别为1到n的数组有多少个。
第一个样例
2
5 5
子数组有[5],[5],[5 5]三个,这三个组最少可以分别分为1 1 1组,使得每个组的任意两个数相乘都是平方数。
思路:
感谢js帮本智障debug。
首先对于一个不为0的数,如果把它的所有完全平方数的因子去掉,那么是不会影响结果的。
所以首先把每个数的完全平方数因子去掉,注意负数的处理!
然后剩下的数都可以表示为一个或者多个质数的乘积,那么两两相乘为平方数只有一种情况,就是两个数字相等。
所以问题转化为了求一个数组的连续子数组中有多少个不相等的数字,那么这个子数组就可以最少分为几个组。
离散化统计每个区间内的不同的数字就行了,用set或者map会T,不知道为什么。。。复杂度O(n^2)。
注意有0的时候,除非每个元素都是0,否则0可以加入任何一个分组,得特殊处理一下,具体看代码。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <set> 5 #include <math.h> 6 using namespace std; 7 const int N = 500100; 8 int a[N]; 9 int b[N]; 10 int c[N]; 11 bool vis[N]; 12 int mabs(int x) 13 { 14 return x >= 0 ? x : -x; 15 } 16 int main() 17 { 18 int n; 19 int cnt = 0; 20 scanf("%d",&n); 21 for (int i = 0;i < n;i++) 22 { 23 scanf("%d",&a[i]); 24 if (a[i] != 0) cnt++; 25 } 26 if (cnt == 0) 27 { 28 printf("%d ",n * (n + 1) / 2); 29 for (int i = 1;i < n;i++) printf("0 "); 30 } 31 else 32 { 33 for (int i = 0;i < n;i++) 34 { 35 if (a[i] == 0) continue; 36 int tmp = mabs(a[i]); 37 for (int j = 2;j * j <= tmp;j++) 38 { 39 int t = j * j; 40 while (a[i] % t == 0) 41 { 42 a[i] /= t; 43 } 44 //if (a[i] < t) break;加了这个就wa,卡了一晚上,考虑的应该是绝对值的情况 45 } 46 } 47 for (int i = 0;i < n;i++) c[i] = a[i]; 48 sort(c,c+n); 49 int js = unique(c,c+n) - c; 50 for (int i = 0;i < n;i++) 51 { 52 if (a[i] == 0) continue; 53 int p = lower_bound(c,c+js,a[i]) - c + 1; 54 a[i] = p; 55 } 56 for (int i = 0;i < n;i++) 57 { 58 memset(vis,0,sizeof(vis)); 59 int num = 0; 60 for (int j = i;j < n;j++) 61 { 62 if (!vis[a[j]] && a[j] != 0) 63 { 64 num++; 65 vis[a[j]] = 1; 66 } 67 int tt = max(num,1); 68 b[tt]++; 69 } 70 } 71 for (int i = 1;i <= n;i++) 72 { 73 printf("%d ",b[i]); 74 } 75 } 76 return 0; 77 }