传送门
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2027 | Accepted: 650 |
Description
Input
Output
Sample Input
4
2 3 4 5
4
2 4 6 8
7
2 3 4 5 7 6 8
Sample Output
1
0
34
Source
题目大意:
给出n(n<10000)个数,这些数<=10000,让你求的就是 GCD(a,b,c,d) == 1的个数,注意必须是 4 个数
解题思路:
其实这个题一开始做就像暴力,可是自己又暴不明白,因为 他把这个题归入容斥原理,所以就考虑GCD(a,b,c,d) == 1的反面就是 GCD(a,b,c,d) != 1,那么a, b, c, d 必定有同样的因子,所以 :
第一步:计算n个数字选四个总共有多少种选法[ C(n,4) ],然后减去公约数不是1的。
第二步:由一个素因子组合成的四个数的组合数 + 由两个素因子组合成的四个数的组合数 -....+..(奇加偶减)
第三步:进行二进制枚举,在枚举的时候要用到两个数组 ,_cnt[]:记录当前因子是由多少个素因子组成, sum[]:记录当前因子的个数
第四步:我们先考虑将每一个数 进行素因子分解,在这里完全可以采用暴力也就是 O(sqrt(n))的算法,因为数据不是很大,当然也可以直接进行素数筛,我采用的就是素数筛。
最后一步:假设a是2的因子的个数,b是3的因子的个数,c是6的因子的个数,就是C(n,4) - C(a,4) - C(b,4) + C(c,4)
容斥原理,与第一步差不多...
PS:我还用了输入输出外挂,果然快呀 ^_^
My Code:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1e4+5; typedef long long LL; int Scan()///输入外挂 { int res=0,ch,flag=0; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0'; return flag?-res:res; } void Out(LL a)///输出外挂 { if(a>9) Out(a/10); putchar(a%10+'0'); } int p[MAXN]; bool prime[MAXN]; int k; void isprime()///素数筛 { k = 0; LL i, j; memset(prime,false,sizeof(prime)); for(i=2; i<MAXN; i++) { if(!prime[i]) { p[k++] = i; for(j=i*i; j<MAXN; j+=i) prime[j] = true; } } } int fac[MAXN/100],num[100], cnt; void Dec(int m)///素因子分解 { cnt = 0; memset(num, 0, sizeof(num)); for(int i=0; p[i]*p[i]<=m&&i<k; i++) { if(m%p[i]==0) { fac[cnt] = p[i]; while(m%p[i]==0) {num[cnt]++; m /= p[i]; } cnt++; } } if(m > 1) { fac[cnt] = m; num[cnt++]=1; } ///cout<<cnt<<endl; ///cout<<fac[0]<<" "<<fac[1]<<endl; } int sum[MAXN];///记录当前因子的个数 int _cnt[MAXN];///记录当前因子是由多少个素因子组成 void Get(int m) { Dec(m); for(int i=1; i<(1<<cnt); i++) { int s = 0; LL ans = 1; for(int j=0; j<cnt; j++) { if(i & (1<<j)) { s++; ans *= fac[j]; if(ans > m) break; } } sum[ans]++; _cnt[ans] = s; } } LL ak[MAXN];///C(n,4) void RongChi() { memset(ak,0,sizeof(ak)); for(LL i=4; i<MAXN; i++) ak[i] = i*(i-1)*(i-2)*(i-3)/24; } int main() { RongChi(); isprime(); ///Dec(1); int n, x; while(~scanf("%d",&n)) { memset(sum, 0, sizeof(sum)); int m = n; while(m--) { x = Scan(); Get(x); } LL ret = 0; for(int i=0; i<MAXN; i++) { if(sum[i]) { if(_cnt[i] & 1) ret += ak[sum[i]]; else ret -= ak[sum[i]]; } } LL ans = ak[n] - ret; Out(ans); puts(""); } return 0; }