zoukankan      html  css  js  c++  java
  • HDU 1695 GCD (容斥原理+欧拉函数)

    题目链接

    题意 : 从[a,b]中找一个x,[c,d]中找一个y,要求GCD(x,y)= k。求满足这样条件的(x,y)的对数。(3,5)和(5,3)视为一组样例 。

    思路 :要求满足GCD(x,y)=k的对数,则将b/k,d/k,然后求GCD(x,y)=1的对数即可。假设b/k >= d/k ;对于1到b/k中的某个数s,如果s<=d/k,则因为会有(x,y)和(y,x)这种会重复的情况,所以这时候的对数就是比s小的与s互质的数的个数,即s的欧拉函数。至于重复的情况是指:在d/k中可能有大于s的与d/k互质的数,但是当你把这些加上了之后,当你继续在b/k中找完s之后再找比s大的数的时候会产生和之前加上的情况重复的情况。

    当s > d/k时,s分解质因数后,质因数的次数不影响结果。我们看另外那个区间有多少个和s不互质(减一下就好了),于是我们只要看另外那个区间中有多少个数是s质因数的倍数就好了。区间[1..a]中 p的倍数 显然有 a/p个。 我们枚举s的质因数利用容斥原理:看另外那个区间有多少个数与s不互质。

    容斥原理的具体如下:

              区间中与s不互质的个数 = (区间中s的每个质因数的倍数个数)-(区间中s的每两个质因数乘积的倍数)+(区间中s的每3个质因数的成绩的倍数个数)-(区间中s的每4个质因数的乘积)+...

              于是问题变成了统计每个数的不同质因数的个数而忽略次数。这个可以用筛法。具体做法如下:

              对每个数保存一个真质因数的列表。初始每个列表的长度为0。然后从2开始,分别检查每个数的列表长度,如果列表长度不为0,则这个数是合数,跳过;如果这个长度为0,则我们找到了一个质数,同时再把这个数的倍数(不包含本身)的列表里加入这个数。

    参考

     1 //1695
     2 #include <iostream>
     3 #include <string.h>
     4 #include <stdio.h>
     5 
     6 using namespace std ;
     7 
     8 int a,b,c,d,k,zh[100010][10],sh[100010] ;
     9 __int64 ans,eu[100010] ;
    10 
    11 void eular()
    12 {
    13     eu[1] = 1 ;
    14     for(int i = 2 ; i < 100010 ; i++)
    15     {
    16         if(!eu[i])
    17         {
    18             for(int j = i ; j < 100010 ; j += i)
    19             {
    20                 if(!eu[j]) eu[j] = j ;
    21                 eu[j] = eu[j] / i * (i-1) ;
    22                 zh[j][sh[j]++] = i ;
    23             }
    24         }
    25         eu[i] += eu[i-1] ;
    26     }
    27 }
    28 __int64 dfs(int s ,int b,int i)
    29 {
    30     __int64 ans1 = 0 ;
    31     for (int j = s ;j < sh[i] ; j++)
    32     {
    33         ans1 += b /zh[i][j] - dfs(j+1,b/zh[i][j],i);
    34     }
    35     return ans1;
    36 }
    37 int main()
    38 {
    39     int T ;
    40     scanf("%d",&T) ;
    41     int cas = 1 ;
    42     eular() ;
    43     while(T--)
    44     {
    45         scanf("%d %d %d %d %d",&a,&b,&c,&d,&k) ;
    46         if(k == 0){
    47             printf("Case %d: 0
    ",cas++) ;
    48             continue ;
    49         }
    50         int maxx = max(b,d) ;
    51         int minn = min(b,d) ;
    52         maxx /= k ;
    53         minn /= k ;
    54         ans = eu[minn] ;
    55         for(int i = minn + 1 ; i <= maxx ; i++)
    56             ans += minn - dfs(0,minn,i) ;
    57         printf("Case %d: %I64d
    ",cas++,ans) ;
    58     }
    59     return 0 ;
    60 }
    View Code
  • 相关阅读:
    LAMP课程(3)
    LAMP课程
    vim文本编辑
    mysql常用语句
    mysql双机互相备份
    Java NIO
    适配器模式
    对象的序列化与反序列化
    字符流
    Java Socket
  • 原文地址:https://www.cnblogs.com/luyingfeng/p/3748901.html
Copyright © 2011-2022 走看看