zoukankan      html  css  js  c++  java
  • 【hdu4135】【hdu2841】【hdu1695】一类通过容斥定理求区间互质的方法

    【HDU4135】Co-prime

      题意

      给出三个整数N,A,B。问在区间[A,B]内,与N互质的数的个数。其中N<=10^9,A,B<=10^15。

      分析

      容斥定理的模板题。可以通过容斥定理求出[1,n]与x互质的数的个数。方法是先将x进行质因子分解,然后对于每个质因子pi,[1,n]内可以被pi整除的数目为n/pi。可以通过容斥定理解决逆命题,既[1,n]与x不互质的数目。n/p1+n/p2+n/p3-n/p1p2-n/p1p3-n/p2p3+n/p1p2p3。既奇数是加,偶数是减。具体的做法一般是通过二进制枚举来进行。质因子分解N的时间复杂度是O(sqrt(N)),然后枚举质因子的时间复杂度是O(2^(num)),其中num是质因子的数目。我们知道,这个num一般来说是非常小的,所以这个算法的时间复杂度是非常优秀的。

      然后对于这个题,我们求出[1,B]与N互质的个数再减去[1,A]互质的个数。

      code如下

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 typedef long long LL;
     8 int T,N,num;
     9 LL A,B;
    10 int a[100];
    11 void prime(int n){
    12     num=0;
    13     for(int i=2;i*i<=n;i++){
    14         if((n%i)==0){
    15             num++;
    16             a[num]=i;
    17             while((n%i)==0){
    18                 n/=i;
    19             }
    20         }
    21     }
    22     if(n>1){
    23         num++;
    24         a[num]=n;
    25     }
    26     return ;
    27 }
    28 LL solve(LL r,int n){
    29     prime(n);
    30     LL res=0;
    31     for(int i=1;i<(1<<num);i++){
    32         int kk=0;
    33         LL div=1;
    34         for(int j=1;j<=num;j++){
    35             if(i&(1<<(j-1))){
    36                 kk++;
    37                 div*=a[j];
    38             }
    39         }
    40         if(kk%2)
    41             res+=r/div;
    42         else
    43             res-=r/div;
    44     }
    45     return r-res;
    46 }
    47 int main(){
    48     scanf("%d",&T);
    49     for(int t=1;t<=T;t++){
    50         scanf("%lld%lld%d",&A,&B,&N);
    51         LL ans=solve(B,N)-solve(A-1,N);
    52         printf("Case #%d: %lld
    ",t,ans);
    53     }
    54 return 0;
    55 }
    View Code

    【HDU2841】visible tree

      题意

      有一片树林m*n,从(1,1)开始,每个整数点都有一棵树。famer站在点(0,0),问他能看见的树有几棵。其中n,m<=100000.

      分析

      先来看有哪些树没有办法被看到。对于点(xi,yi),当xi和yi可以同时被一个大于1的整数k整除,则点(xi,yi)无法被看到。也就是说,当且仅当这个点的横纵坐标互质时,才可以被看到。也就是说求[1,n]和[1,m]内有多少互质的点。到此为止,本题已经转换为上一个题的形式。然后枚举[1,m]作为x,然后[1,n]作为区间,按照上题方案进行求解。

      code 如下

      

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 typedef long long LL;
     8 int T,n,m,num;
     9 int a[20];
    10 void prime(int x){
    11     num=0;
    12     for(int i=2;i*i<=x;i++){
    13         if(x%i==0){
    14             num++;
    15             a[num]=i;
    16             while(x%i==0&&x){
    17                 x/=i;
    18             }
    19         }
    20     }
    21     if(x>1){
    22         num++;
    23         a[num]=x;
    24     }
    25     return;
    26 }
    27 LL solve(LL r,int x){
    28     LL res=0;
    29     for(int i=1;i<(1<<num);i++){
    30         LL k=0,aa=1;
    31         for(int j=1;j<=num;j++){
    32             if(i&(1<<(j-1))){
    33                 k++;
    34                 aa*=a[j];
    35             }
    36         }
    37         if(k%2)
    38             res+=r/aa;
    39         else
    40             res-=r/aa;
    41     }
    42     return r-res;
    43 }
    44 int main(){
    45     scanf("%d",&T);
    46 
    47     for(int t=1;t<=T;t++){
    48         scanf("%d%d",&n,&m);
    49         if(n>m)swap(n,m);
    50         LL ans=0;
    51 
    52         for(int i=1;i<=n;i++){
    53             prime(i);
    54             ans+=solve(m,i);
    55             //cout<<solve(m,i)<<endl;
    56         }
    57         printf("%lld
    ",ans);
    58     }
    59 return 0;
    60 }
    View Code
     

    【HDU1695】GCD

     题意

     给出a,b,c,d,k,其中保证a=1,c=1。问在区间[a,b]和区间[c,d]内有多少不同的对gcd(x,y)=k。

     分析

     如果gcd(x,y)=k,则显然gcd(x/k,y/k)=1,既互质。我们令b<d,然后b/=k,d/=k。则题目转化为在区间[1,b]和区间[1,d]有多少不同对互质。

     有没有感觉和上面那道题很像?就一个不同点,这个题目求的是不同对。所以不可以按照上面这个题直接进行枚举。对于区间[1,b],我们可以直接枚举求和欧拉函数。对于区间[b+1,d]我们可以按照上面的方法通过容斥定理进行求解。

     code如下

      

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 typedef long long LL;
     8 
     9 int T,a,b,c,d,k;
    10 LL ans;
    11 int euler(int n){ //返回euler(n)
    12      int res=n,aa=n;
    13      for(int i=2;i*i<=aa;i++){
    14          if(aa%i==0){
    15              res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
    16              while(aa%i==0) aa/=i;
    17          }
    18      }
    19      if(aa>1) res=res/aa*(aa-1);
    20      return res;
    21 }
    22 int num;
    23 int pri[20];
    24 void prime(int x){
    25     num=0;
    26     for(int i=2;i*i<=x;i++){
    27         if(x%i==0){
    28             num++;
    29             pri[num]=i;
    30             while(x%i==0){
    31                 x/=i;
    32             }
    33         }
    34     }
    35     if(x>1){
    36         num++;
    37         pri[num]=x;
    38     }
    39 }
    40 LL solve(LL r,int x){
    41     LL res=0;
    42     for(int i=1;i<(1<<num);i++){
    43         int k=0,aa=1;
    44         for(int j=1;j<=num;j++){
    45             if(i&(1<<(j-1))){
    46                 k++;
    47                 aa*=pri[j];
    48             }
    49         }
    50         if(k%2)
    51             res+=r/aa;
    52         else
    53             res-=r/aa;
    54     }
    55     return r-res;
    56 }
    57 int main(){
    58     scanf("%d",&T);
    59     for(int t=1;t<=T;t++){
    60         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    61         if(k==0){
    62             printf("Case %d: 0
    ",t);
    63             continue;
    64         }
    65         if(b>d)swap(b,d);
    66         b/=k,d/=k;
    67         ans=0;
    68         for(int i=1;i<=b;i++){
    69             ans+=euler(i);
    70         }
    71         for(LL i=b+1;i<=d;i++){
    72             prime(i);
    73             ans+=solve(b,i);
    74         }
    75         printf("Case %d: %lld
    ",t,ans);
    76     }
    77 return 0;
    78 }
    View Code

      

  • 相关阅读:
    LeetCode236. 二叉树的最近公共祖先
    LeetCode235. 二叉搜索树的最近公共祖先
    LeetCode第32场双周赛
    .NET+Vue 使用SignalR推送数据
    Asp.Net Core使用MongoDB
    CentOS8 部署SqlServer
    windows 任何软件出现异常有日志 w3wp.exe [10608]中发生了未处理的Microsoft .Net Framework异常
    C# Socket使用以及DotNetty和Supersocket 框架
    C# 数据结构与算法 操作系统原理 计算机网络原理 数据库开发学习
    DotNet .Net Framework与Net Core与Net Standard 以及.NET5
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9051510.html
Copyright © 2011-2022 走看看