POJ 3904 Sky Code

题意:给定n个数ai, ai <= 10000, n <= 10000, 从中选出4个数要求gcd为1,这样的集合有多少个?

分析:首先总共集合nCr(n, 4) = n*(n-1)*(n-2)*(n-3)/24个,那么需要减掉gcd >=2 的集合。先减掉gcd为各个素数的方案数目,然后再由这些素数组成一些因子,考虑gcd为这些因子的情况。最后总结起来就是,素数个数为奇数时,减去;素数个数为偶数时,加上。具体实现的时候只要对每个ai分解质因数,然后单独考虑他的素因子能组成哪些数,这样再计算。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <map>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cmath>
 7 #define pb push_back
 8 #define mp make_pair
 9 #define esp 1e-8
10 #define lson   l, m, rt<<1
11 #define rson   m+1, r, rt<<1|1
12 #define sz(x) ((int)((x).size()))
13 #define pb push_back
14 #define in freopen("solve_in.txt", "r", stdin);
15 #define bug(x) printf("Line : %u >>>>>>
", (x));
16 #define inf 0x7f7f7f7f
17 using namespace std;
18 typedef long long LL;
19 typedef map<int, int> MPS;
20 typedef pair<int, int> PII;
21 
22 const int maxn = 10000 + 10;
23 int a[maxn];
24 LL vis[22][maxn], p[22], pa[22];
25 int cnt;
26 void dfs(int st, int pos, int lim) {
27     if(pos == lim) {
28         int tmp = 1;
29         for(int i = 0; i < pos; i++)
30             tmp *= pa[i];
31         vis[lim][tmp]++;
32         return;
33     }
34     for(int i = st; i < cnt; i++) {
35         pa[pos] = p[i];
36         dfs(i+1, pos+1, lim);
37     }
38 }
39 int main() {
40 
41     int n;
42     while(scanf("%d", &n) == 1) {
43         memset(vis, 0, sizeof vis);
44         for(int i = 1; i <= n; i++) {
45             scanf("%d", a+i);
46             int x = a[i];
47             cnt = 0;
48             for(int j = 2; j*j <= x; j++) {
49                 if(x%j == 0) {
50                     p[cnt++] = j;
51                     while(x%j == 0)
52                         x /= j;
53                 }
54             }
55             if(x != 1)
56                 p[cnt++] = x;
57             for(int j = 1; j <= cnt; j++)
58                 dfs(0, 0, j);
59         }
60         double ans = 1.0*n*(n-1)*(n-2)*(n-3)/24;
61         for(int i = 1; i < 22; i++)
62             for(int j = 2; j <= 10000; j++)
63                 if(vis[i][j] >= 4) {
64                     double tmp = 1.0;
65                     for(LL k = vis[i][j]; k > vis[i][j]-4; k--)
66                         tmp = tmp*k;
67                     tmp /= 24;
68                     ans += ((i&1) ? -1 : 1)*tmp;
69                 }
70         printf("%.0f
", ans);
71     }
72     return 0;
73 }
View Code

 UPD:这题还可以用扩展欧拉函数做?链接:http://scturtle.is-programmer.com/posts/19402.html

其实是概率角度解释解释欧拉函数,然后拓展一下就可以解这个题了。1/p为包含素因子p的概率。1/p^n为n个数都包含素因子p的概率。

ans = m^n * ∏(1-1/(p^n))

原文地址:https://www.cnblogs.com/rootial/p/4082340.html