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 >>>>>>\n", (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\n", ans); 71 } 72 return 0; 73 }
UPD:这题还可以用扩展欧拉函数做?链接:http://scturtle.is-programmer.com/posts/19402.html
其实是概率角度解释解释欧拉函数,然后拓展一下就可以解这个题了。1/p为包含素因子p的概率。1/p^n为n个数都包含素因子p的概率。
ans = m^n * ∏(1-1/(p^n))