Codeforces Round #429 (Div. 2) E. 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 < n condition, 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.

 

 

题意 :求相邻的元素相乘不为平方数的方案数(a[0]=a[1]=1, 视 a[0] 与 a[1]  不同)

思路 :

    每个数可以表示为  p1^a1 * p2^a2 * .....

    如果 两个数A,B相乘为平方数 则   a1%2 = a1' %2  ,  a2%2 = a2'%2 .....

    即 对应质因子的幂次 奇偶性相同 这样就可以划分出T组 

    然后题目就转化为 T种物品 相同种类物品不能放在相邻 求方案数

    这题就变成原题 :https://csacademy.com/contest/archive/task/distinct_neighbours/statement/

            http://acm.hdu.edu.cn/showproblem.php?pid=6116

    做法为dp

    dp [ i ] [ j ]  表示  插入第 i 组的物品 出现了 左右为相同物品的空隙个数为 j   的方案数

    那 dp [ T ]  [ 0 ]  就是最终答案了

    附: cs官方题解 (原题的题解)

 

      First we group all the distinct values in the array. Then we can solve the problem using dynamic programming:

      Let dp[i][j] = the number of distinct arrays that can be obtained using the elements of the first i groups such that there are exactly j pairs of consecutive positions having the same value. The answer can be found in dp[distinctValues][0].

      Now let's say the sum of frequences of the first i values is X. This means the arrrays we can build using the elements from these i groups have size X, so we can insert the elments of group i + 1 in X + 1 gaps: before the first element, after the last, and between any two consecutive. We can fix the number k of gaps where we want to insert at least one element from group i + 1, but we also need to fix the number l of these k gaps which will be between elements that previously had the same value. State dp[i][j] will update the state dp[i + 1][j - l + frequence[i + 1] - k].

      The number of ways of choosing k gaps such that exactly l are between consecutive elements having the same value can be computed easily using combination formulas. We  are left with finding out the number of ways of inserting frequence[i + 1] elements in k gaps. This is also a classical problem with a simple answer: Comb(frequence[i + 1] - 1, k - 1). 

 

    具体转移方程见代码 :

    

    

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <functional>

#define mp make_pair
#define pb push_back
#define mes(a,b) memset(a,b,sizeof(a))
#define mes0(a) memset(a,0,sizeof(a))
#define lson l,mid,pos<<1
#define rson mid+1,r,pos<<1|1
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define fi first
#define se second
#define sss(a) a::iterator
#define all(a) a.begin(),a.end()

using namespace std;

typedef double DB;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<long long ,int> pli;
typedef pair<int,long long > pil;
typedef pair<string,int> psi;
typedef pair<long long ,long long > pll;

const int inf = 0x3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const int maxn = 100000+10;
const int mod = 1e9+7;
LL dp[500][500];
LL C[500][500];
LL fact[500];
int cnt[500];
int a[500];
int vis[500];
int sz;
int check(LL x)
{
    LL l=1,r=1e9;
    LL now=l;
    while (l<=r){
        LL mid=(l+r)>>1;
        if (mid*mid<=x)now=mid,l=mid+1;
        else r=mid-1;
    }
    return now*now==x;
}
inline LL M(LL x)
{
    return x%mod;
}
void init()
{
    C[0][0]=1;
    fact[0]=1;
    for (int i=1;i<=300;i++){
        C[i][0]=1;
        for (int j=1;j<=i;j++){
            C[i][j]=M(C[i-1][j]+C[i-1][j-1]);
        }
    }
    for (int i=1;i<=300;i++)fact[i]=M(fact[i-1]*i);
}
void slove()
{
    dp[0][cnt[0]-1]=1;
    int lim=cnt[0];
    for (int i=1;i<sz;i++){
        for (int j=0;j<lim;j++){  /// dp[i-1][j]
            for (int k=0;k<cnt[i];k++){/// group[i]分成k+1组 ,cnt[i]-1-k个空隙
                for (int m=0;m<=min(j,k+1);m++){ /// 选了m个左右相同的空隙插入
                    dp[i][j+cnt[i]-1-k-m]=M(dp[i][j+cnt[i]-1-k-m]+dp[i-1][j]*C[cnt[i]-1][k]%mod*C[j][m]%mod*C[lim-1-j+2][k+1-m]);
                }
            }
        }
        lim+=cnt[i];
    }
    LL ans=dp[sz-1][0];
    for (int i=0;i<sz;i++){
        ans*=fact[cnt[i]];
        ans%=mod;
    }
    cout<<ans<<endl;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        scanf("%d",a+i);
    }
    for (int i=0;i<n;i++){
        if (vis[i]==0){
            for (int j=i;j<n;j++){
                if (check(1LL*a[i]*a[j])){
                    cnt[sz]++;
                    vis[j]=1;
                }
            }
            sz++;
        }
    }
    init();
    slove();
    return 0;
}

 

posted @ 2017-08-20 04:44  orz010orz  阅读(758)  评论(4编辑  收藏  举报