C. On the Bench
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
A year ago on the bench in public park Leha found an array of n numbers. Leha believes that permutation p is right if for all 1 ≤ i < ncondition, that api·api + 1 is not perfect square, holds. Leha wants to find number of right permutations modulo 109 + 7.
Input
First line of input data contains single integer n (1 ≤ n ≤ 300) — length of the array.
Next line contains n integers a1, a2, ... , an (1 ≤ ai ≤ 109) — found array.
Output
Output single integer — number of right permutations modulo 109 + 7.
Examples
input
3
1 2 4
output
2
input
7
5 2 4 2 4 1 1
output
144
Note
For first example:
[1, 2, 4] — right permutation, because 2 and 8 are not perfect squares.
[1, 4, 2] — wrong permutation, because 4 is square of 2.
[2, 1, 4] — wrong permutation, because 4 is square of 2.
[2, 4, 1] — wrong permutation, because 4 is square of 2.
[4, 1, 2] — wrong permutation, because 4 is square of 2.
[4, 2, 1] — right permutation, because 8 and 2 are not perfect squares.
题解:dp
一个简单的性质:a*b为完全平方数,b*c为完全平方数,那么a*c也是完全平方数
将两两相乘等于完全平方数的数放入一组,设一共有sz组,每一组有cnt[i]个数
设dp[i][j]为当前一共放了i组数,有j对连续的数是同一组的(即其中需要插入某个不是同一组的数,以下称作间隙)
设q为将第i组数分成q份,则其中有cnt[i]-q个间隙
设p为从这q份中选p份插入间隙中,其它的不插入间隙
设m为前i组数一共有m个数字,有m+1个位置可以插入数字
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define per(i,a,b) for(int i=a-1;i>=(b);--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define clr(a,b) memset(a,b,sizeof(a))
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 1e9 + 7;
const int MX = 305;
ll F[MX], invF[MX];
ll power(ll a, ll b) {
ll ret = 1;
while(b) {
if(b & 1) ret = (ret * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ret;
}
void init() {
F[0] = 1;
for(int i = 1; i < MX; i++) F[i] = (F[i - 1] * i) % mod;
invF[MX - 1] = power(F[MX - 1], mod - 2);
for(int i = MX - 2; i >= 0; i--) {
invF[i] = invF[i + 1] * (i + 1) % mod;
}
}
ll C(int n, int m) {
if(n < 0 || m < 0 || m > n) return 0;
if(m == 0 || m == n) return 1;
return F[n] * invF[n - m] % mod * invF[m] % mod;
}
ll a[MX];
int cnt[MX], vis[MX];
bool check(ll x) {
ll l = 1, r = 1e9;
while(l <= r) {
ll m = (l + r) >> 1;
if(m * m == x) return 1;
if(m * m < x) l = m + 1;
else r = m - 1;
}
return r * r == x;
}
ll dp[MX][MX];
int pre[MX];
inline ll mul(ll a, ll b, ll c) {return a * b % mod * c % mod;}
int main() {
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
init();
int n; cin >> n;
rep(i, 0, n) cin >> a[i];
int sz = 0;
rep(i, 0, n) if(!vis[i]) {
rep(j, i, n) if(!vis[j] && check(a[i]*a[j])) cnt[sz]++, vis[j] = 1;
sz++;
}
pre[0] = cnt[0]; rep(i, 1, sz) pre[i] = pre[i - 1] + cnt[i];
dp[0][cnt[0] - 1] = F[cnt[0]];
rep(i, 1, sz) {
rep(j, 0, pre[i - 1]) rep(q, 1, cnt[i] + 1) rep(p, 0, min(j + 1, q + 1)) {
int k = j - p + cnt[i] - q;
dp[i][k] += dp[i - 1][j] * mul(C(cnt[i] - 1, q - 1), C(j, p), C(pre[i - 1] + 1 - j, q - p)) % mod;
if(dp[i][k] >= mod) dp[i][k] -= mod;
}
rep(j, 0, pre[i]) dp[i][j] = dp[i][j] * F[cnt[i]] % mod;
}
cout << dp[sz - 1][0] << endl;
return 0;
}