补坑之路之两道容斥原理的基本模型题:HDU 4135&&HDU1796

Co-prime

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1517    Accepted Submission(s): 581


Problem Description
Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
 

Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 10 15) and (1 <=N <= 10 9).
 

Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.
 

Sample Input
  
  
2 1 10 2 3 15 5
 

Sample Output
  
  
Case #1: 5 Case #2: 10
Hint
In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.
 

Source
The Third Lebanese Collegiate Programming Contest

最基本的模型:求[L,R]中与N互质的元素个数。
思路:容斥原理先考虑反面求与N不互质的个数,对N质因子分解,然后形成N的所有质因子的集合,然后枚举,进行容斥最后拿1-R中与N不互质的-1-L-1与N不互质的就OK了。
写不来DFS,只能用啥二进制暴力写了。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

vector<long long> v;
long long a,b,n;

long long solve(long long x,long long n)
{

    v.clear();
    for(long long  i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            v.push_back(i);
            while(n%i==0)
            {
                n/=i;
            }
        }

    }
     if(n>1)
        v.push_back(n);
    long long sum=0;
    long long cnt;
    long long lcm;
    for(long long  i=1;i<(1<<v.size());i++)//用二进制来1,0来表示第几个素因子是否被用到,如m=3,三个因子是2,3,5,则i=3时二进制是011,表示第2、3个因子被用到
    {
        cnt=0;
        lcm=1;
        for(long long  j=0;j<v.size();j++)
        {
            if(i&(1<<j)) //判断第几个因子目前被用到
            {
                lcm*=v[j];
                cnt++;
            }
        }
        if(cnt%2==0)
            sum-=x/lcm;
        else
            sum+=x/lcm;
    }
    return x-sum;
}
int  main()
{
    long long  t;
    cin>>t;
    long long  cas=0;
    while(t--){
        scanf("%I64d%I64d%I64d",&a,&b,&n);
        printf("Case #%I64d: %I64d\n",++cas,solve(b,n)-solve(a-1,n));
    }
    return 0;
}

How many integers can you find

Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4298    Accepted Submission(s): 1233


Problem Description
  Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
 

Input
  There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
 

Output
  For each case, output the number.
 

Sample Input
   
   
12 2 2 3
 

Sample Output
   
   
7
 

Author
wangye
 

Source
2008 “Insigma International Cup” Zhejiang Collegiate Programming Contest - Warm Up(4)
题意及思路:

求在给定区间内,能被给定集合至少一个数整除的数个数

       给出n个整数ai和整数r。求在区间[1;r]中,至少能被一个ai整除的数有多少。

         解决此题的思路和上题差不多,计算ai所能组成的各种集合(这里将集合中ai的最小公倍数作为除数)在区间中满足的数的个数,然后利用容斥原理实现加减。

         此题中实现所有集合的枚举,需要2^n的复杂度,求解lcm需要O(nlogr)的复杂度。

与上题换汤不换药,都属于经典的容斥原理的模型,不过要注意除去元素为0的情况,再进行容斥。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const long long  maxn=15;

long long  n,m;
long long  a[maxn];
long long  b[maxn];
long long  gcd(long long  a,long long  b)
{
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}

long long  lcm(long long  a,long long  b)
{
    return a/gcd(a,b)/b;
}

int main()
{
    while(cin>>n>>m)
    {
        for(int i=0;i<m;i++)
        {
            cin>>a[i];
        }
        n--;
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            if(a[i]!=0)
            {
                b[cnt++]=a[i];
            }
        }
        long long res=0;
        for(int i=1;i<(1<<cnt);i++)
        {
            long long  num=0;
            long long LCM=1;
            for(int j=0;j<cnt;j++)
            {
                if(i&(1<<j))
                {
                    num++;
                    LCM=LCM/gcd(LCM,a[j])*(a[j]);
                }


            }
            if(num%2==0) res-=n/LCM;
            else res+=n/LCM;
        }
        cout<<res<<endl;
    }
    return 0;
}
坑还得慢慢补,http://www.haogongju.net/art/1724838这个地方的文章写得很好,我就是照着这个慢慢看的,容斥原理貌似是莫比乌斯反演的一个特例?。。。也许广州赛区不会考到= =但是以后应该还是会碰到的,重在思维,可惜不会DFS,好忧桑。。。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值