hdu5072 Coprime (2014鞍山区域赛C题)(数论)

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

题意:给出N个数,求有多少个三元组,满足三个数全部两两互质或全部两两不互质。

题解:

http://dtyfc.com/acm/980 我看的这个学会的……

可以先求不满足要求的三元组数量,也就是abc,a和b互质,b和c不互质。

这样就要找这n个数中,和某个数不互质的数的个数。

可以质因数分解+容斥原理,求出和某个数不互质的数的个数(也就是和这个数有相同因数的数的个数)。

还要先预处理以某个数x为因子的数的个数,cnt[x]。

具体看代码。

其实我也不是很熟,醉了。

不信你看这个博客都没有数论分类

 

代码:

  1 //#pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<queue>
 12 #include<ctime>
 13 using namespace std;
 14 #define mz(array) memset(array, 0, sizeof(array))
 15 #define mf1(array) memset(array, -1, sizeof(array))
 16 #define minf(array) memset(array, 0x3f, sizeof(array))
 17 #define REP(i,n) for(i=0;i<(n);i++)
 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
 19 #define RD(x) scanf("%d",&x)
 20 #define RD2(x,y) scanf("%d%d",&x,&y)
 21 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 22 #define WN(x) printf("%d\n",x);
 23 #define RE  freopen("D.in","r",stdin)
 24 #define WE  freopen("huzhi.txt","w",stdout)
 25 #define mp make_pair
 26 #define pb push_back
 27 #define pf push_front
 28 #define ppf pop_front
 29 #define ppb pop_back
 30 typedef long long ll;
 31 typedef unsigned long long ull;
 32 
 33 const double pi=acos(-1.0);
 34 const double eps=1e-10;
 35 
 36 const int maxn=111111;
 37 
 38 int a[maxn];
 39 int cnt[maxn];
 40 int n;
 41 
 42 int b[maxn],bn;
 43 
 44 int att,me;
 45 inline void attack(const int &now,const int &sum,const int &flag) {
 46     if(now==bn) {
 47         if(sum==1)return;
 48 //        printf("sum=%d cnt[]=%d flag=%d\n",sum ,(cnt[sum]), flag);
 49         att+=flag*(cnt[sum]);
 50         return;
 51     }
 52     attack(now+1,sum,flag);
 53     attack(now+1,sum*b[now],-flag);
 54 }
 55 
 56 
 57 ll farm() {
 58     int i,j,k;
 59     mz(cnt);
 60     FOR(i,1,100000)
 61     for(j=i; j<=100000; j+=i)
 62         cnt[i]+=a[j];
 63     ll sm=0;
 64     FOR(i,1,100000) {
 65         if(a[i]) {
 66             int s=(int)sqrt((double)i);
 67             int t=i;
 68             bn=0;
 69             for(j=2; j<=s && t>1; j++){
 70                 if(t%j==0){
 71                     b[bn++]=j;
 72                     while(t%j==0)t/=j;
 73                 }
 74             }
 75             if(t>1)b[bn++]=t;
 76             att=0;
 77             me=i;
 78             attack(0,1,-1);
 79 //            REP(j,bn)printf("%d,",b[j]);
 80 //            printf("(i=%d , att= %d re+=%d)\n",i,att,max(0 , att-1) * (n-att));
 81             sm+=(ll)max(0 , att-1) * (n-att);
 82         }
 83     }
 84     return (ll)n*(n-1)*(n-2)/6 - sm/2;
 85 }
 86 
 87 
 88 int main() {
 89     int T,i,x;
 90     RD(T);
 91     while(T--) {
 92         RD(n);
 93         mz(a);
 94         REP(i,n) {
 95             RD(x);
 96             a[x]++;
 97         }
 98         printf("%I64d\n",farm());
 99     }
100     return 0;
101 }
View Code

 

转载于:https://www.cnblogs.com/yuiffy/p/4054271.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值