Codeforces-840C On the Bench(dp)

来源:互联网 发布:v盾网络验证破解 编辑:程序博客网 时间:2024/06/04 01:21

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
31 2 4
output
2
input
75 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

将两两相乘等于完全平方数的数放入一组,设一共有sz组,每一组有cnt[i]个数

设dp[i][j]为当前一共放了i组数,有j对连续的数是同一组的(即其中需要插入某个不是同一组的数,一下称作间隙)

设k为将第i组数分成k+1份,则其中有cnt[i]-1-k个间隙

设p为从这k份中选p份插入间隙中,其它的不插入间隙

设m为前i组数一共有m+1个数字,有m个位置可以插入数字

dp[i][j+cnt[i]-1-k-p]=dp[i-1][j]*C(cnt[i]-1,k)*C(j,p)*C(m+2-j,k+1-p)

#include<bits/stdc++.h>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define x first#define y secondusing namespace std;typedef long long LL;typedef pair<int, int> PII;const int MX = 305;const LL mod = 1e9 + 7;LL dp[MX][MX], f[MX], invf[MX];LL pow(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] = pow(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;}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 0;}LL a[305];int sz, cnt[MX], vis[MX];int main() {    init();    int n;    //freopen("in.txt", "r", stdin);    scanf("%d", &n);    for (int i = 1; i <= n; i++) scanf("%I64d", &a[i]);    for (int i = 1; i <= n; i++) {        if (vis[i]) continue;        sz++;        for (int j = i; j <= n; j++) {            if (check(a[i]*a[j])) vis[j] = 1, cnt[sz]++;        }    }    int m = cnt[1] - 1;    dp[1][m] = 1;    for (int i = 2; i <= sz; m += cnt[i++]) {        for (int j = 0; j <= m; j++) {//dp[i-1][j]            if (dp[i - 1][j] == 0) continue;            for (int k = 0; k < cnt[i]; k++) {//分成k+1组,有a[i]-1-k个间隙                for (int p = 0; p <= min(k + 1, j); p++) { //插入p个间隙中                    LL tmp = dp[i - 1][j] * C(cnt[i] - 1, k) % mod * C(j, p) % mod * C(m + 2 - j, k + 1 - p) % mod;                    (dp[i][j + cnt[i] - 1 - k - p] += tmp) %= mod;                }            }        }    }    LL ans = dp[sz][0];    for (int i = 1; i <= sz; i++) ans = ans * f[cnt[i]] % mod;    printf("%I64d\n", ans);    return 0;}


原创粉丝点击