/* HDU 4390 Number Sequence -- 容斥原理(不好理解) http://blog.csdn.net/acm_cxlove/article/details/8146102 n种球每种Ai个 {A1, A2, A3...An}放在m个盒子里,盒子不为空有多少种放法 先求出总的放法(允许为空),然后减去至少有一个盒子为空的放发 容斥原理可求出至少有一个盒子为空的放发 画vn图吧 附:函数mBallinTrickn m个球放在n个盒子里有多少种方法(允许有空盒子) */ #pragma comment(linker, "/STACK:102400000,102400000") #include <functional> #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <string> #include <vector> #include <ctime> #include <queue> #include <cmath> #include <set> #define CLR(a,v) memset(a,v,sizeof(a)) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N = 1e5+10; const ll mod = 1e9 + 7; ll C[505][505]; // 组合数 int en[N] , e[N]; int n,num[N]; inline ll inv(ll a,ll mod){ return a==1 ? 1 : inv(mod % a,mod) * (mod - mod/a) % mod;} ll nCr(ll n,ll r){ if(C[n][r]!=-1)return C[n][r]; if(n==r)return 1; if(n<r)return 0; if(r==1)return n; return C[n][r] = (nCr(n-1,r-1) + nCr(n-1,r))%mod; } int divsor(){ // 返回num[] 里面总因子个数 vector<int> s; for(int j = 0 ; j < n ; j++){ for(int i = 2 ; i*i <= num[j] ; i++){ if(num[j]%i == 0){ while(num[j]%i==0) num[j]/=i , s.push_back(i); } } if(num[j]>1) { s.push_back(num[j]); } } sort(s.begin(),s.end()); int cnt=0; e[cnt]=s[0];en[cnt]=1; for(int i = 1 ; i < s.size() ; i++){ if(s[i] != s[i-1]){ e[++cnt]=s[i]; en[cnt]=1; }else{ en[cnt]++; } } return cnt+1; } ll mBallinTrickn(int m,int n){ // 允许trick为空 // ans = nCr(n-1+m , n-1); // A1 > A2 // 需要求逆元函数 ll ret = 1; ll B = n-1+m , A1 = max(n-1,m), A2 = min(n-1,m); for(int i = A2+1 ; i <= B ; i++) ret = ret * i % mod; for(int i = 2 ; i <= A1 ; i++) ret = ret * inv(i,mod) % mod; return ret; } int main(){ // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); CLR(C,-1); while(cin >> n){ CLR(en,0); for(int i = 0; i < n ; i++) scanf("%d",&num[i]); int cnt_div = divsor(); // cnt_div种球 每种en[i]个 放在n个坑里 ll ans = 1; for(int i = 0 ; i < cnt_div ; i++) // 总的方案数(允许盒子为空) ans = ans * mBallinTrickn(en[i],n) % mod; for(int i = 1 ; i < n ; i++){ // 遍历 [1,n) 个坑 int temp = nCr(n,i); for(int j = 0 ; j < cnt_div ; j++){ // 每排除i个坑,遍历一遍各种球 temp = (temp*mBallinTrickn(en[j],n-i)) % mod; } ans = (ans + (i&1?-temp + mod:temp)) % mod ; } printf("%lld\n" , ans); } return 0; }