显然一个正整数$x$可以被表示为$d_{1}\cdot s_{1}^{2}$,其中$d,s\in N_{+}$,$d$取最小值。
另一个正整数$y$表示为$d_{2}\cdot s_{2}^{2}$。那么$xy$是完全平方数的充分必要条件是$d_{1} = d_{2}$。(可以先证明$d$不含平方因子,然后用反证法证明)
然后问题可以转化成有$n$个互不相同的球,每个球被涂有一种颜色,要求将所有球排成一排,同种颜色的球不相邻的方案数。
考虑设$f_{i, j}$表示当前考虑到第$i$种颜色,已经有$j$个连续的段。
每次考虑放入一种颜色的所有球。主要有三种情况:
- 一个球被拿去连接两段球
- 一个球被放入了一个独立的段
- 一个球放在某一段的端点处
我们枚举第一种情况的球的个数。假设第$i$种颜色有$c$个球,原本有$j$段球,现在我要拿$x$球作为第一种情况,拿$y$个球作为第二种情况。(这样根据之前有多少段计算现在有多少段)
- 对于第一部分,首先我需要选择$x$个球,然后在$j - 1$个间隙中选出$x$个间隙,再决定每个球放在哪个间隙。这一部分方案数是$\binom{c}{x}\binom{j - 1}{x}x!$
- 对于第二部分,我需要从剩下的$x - c$个球中选出$y$个球,我先将它排列好,然后分成$j - x$段插入间隙中(这个插入和上面的那种情况不同,这里不会连接两端点)。显然这一部分的方案数是$\binom{c - x}{y}\binom{y + j - x}{j - x}y!$
- 对于第三部分,剩下的球已经是确定的了,不用考虑。我只需要从$2(j - x)$个可选的位置中选择$c - x - y$个位置,然后排列一下把球放上去。
时间复杂度$O(n^{3})$
Code
1 /** 2 * Codeforces 3 * Problem#840C 4 * Accepted 5 * Time: 62ms 6 * Memory: 1800k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 using namespace std; 13 typedef bool boolean; 14 15 const int N = 305, M = 1e9 + 7; 16 17 int add(int a, int b) { 18 return ((a += b) >= M) ? (a - M) : (a); 19 } 20 21 int mul(int a, int b) { 22 return (a * 1ll * b) % M; 23 } 24 25 void exgcd(int a, int b, int& x, int& y) { 26 if (!b) 27 x = 1, y = 0; 28 else { 29 exgcd(b, a % b, y, x); 30 y -= (a / b) * x; 31 } 32 } 33 34 int inv(int a, int n) { 35 int x, y; 36 exgcd(a, n, x, y); 37 return (x < 0) ? (x + n) : (x); 38 } 39 40 int n; 41 int ar[N]; 42 int f[N][N]; 43 int fac[N], _fac[N]; 44 int C[N << 1][N << 1]; 45 46 inline void init() { 47 scanf("%d", &n); 48 for (int i = 1, x, y; i <= n; i++) { 49 scanf("%d", &x), y = 1; 50 for (int p = 2, a = 0; p * p <= x; p++, a = 0) { 51 while (!(x % p)) 52 x /= p, a ^= 1; 53 if (a) 54 y *= p; 55 } 56 if (x > 1) 57 y *= x; 58 ar[i] = y; 59 } 60 } 61 62 inline void solve() { 63 sort(ar + 1, ar + n + 1); 64 C[0][0] = 1; 65 for (int i = 1; i <= (n << 1); i++) { 66 C[i][0] = C[i][i] = 1; 67 for (int j = 1; j < i; j++) 68 C[i][j] = add(C[i - 1][j - 1], C[i - 1][j]); 69 } 70 71 fac[0] = 1; 72 for (int i = 1; i <= n; i++) 73 fac[i] = mul(fac[i - 1], i); 74 _fac[n] = inv(fac[n], M); 75 for (int i = n; i; i--) 76 _fac[i - 1] = mul(_fac[i], i); 77 78 int t = 1; 79 f[0][0] = 1; 80 for (int i = 1, r = i; i <= n; i = r, t++) { 81 while (r <= n && ar[r] == ar[i]) 82 r++; 83 int cnt = r - i; 84 for (int j = 0; j < i; j++) { 85 for (int k = j; k <= j + cnt; k++) { 86 int c_indep = k - j, c_depen = cnt - c_indep; 87 int n_indep = mul(mul(C[cnt][c_indep], fac[c_indep]), C[c_indep + j][j]); 88 int n_depen = mul(C[j * 2][c_depen], fac[c_depen]); 89 f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(n_indep, n_depen))); 90 } 91 // f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(mul(fac[k], _fac[j]), mul(C[j * 2][cnt - k + j], fac[cnt - k + j])))); 92 for (int con = 1; con < j; con++) { 93 for (int k = j - con; k < r; k++) { 94 int c_indep = k - j + con, c_depen = cnt - con - c_indep; 95 if (c_depen < 0) 96 break; 97 int n_conne = mul(C[j - 1][con], mul(C[cnt][con], fac[con])); 98 int n_indep = mul(C[cnt - con][c_indep], mul(fac[c_indep], C[c_indep + j - con][j - con])); 99 int n_depen = mul(C[(j - con) * 2][c_depen], fac[c_depen]); 100 f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(n_conne, mul(n_indep, n_depen)))); 101 // f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(mul(C[j - 1][con], ), mul(fac[j + ind], mul(_fac[j], C[(j - con) * 2][dep]))))); 102 } 103 } 104 } 105 // for (int i = 0; i < r; i++) 106 // cerr << f[t][i] << " " ; 107 // cerr << '\n'; 108 } 109 printf("%d\n", f[t - 1][1]); 110 } 111 112 int main() { 113 init(); 114 solve(); 115 return 0; 116 }