hdu 2841(容斥原理)

  • 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2841

  • 题意:有一个农民,站在(0,0)点,从(1,1)点到(m,n)点每个点上有棵树,问这个农民能看到多少棵树。树被挡就看不到

  • 分析:画个图,我们就能发现一个重大问题,当两点坐标互质时就能看到树,否则就不能。这里我们就可以求解容斥原理,转而求,在1~m中有多少个数与1~n互质。我们先求不互质的个数,设i在1~m之间,进行素因子分解,则小于n能被i的素因子整除的数就不是与i互质的数,这是我们用容斥就可以求出总数。容斥原理详见链接:容斥原理

  • 代码如下:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <utility>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;
long long ans;
int n,m;
struct sa{
    int fen[10];
    int k;
}p[100000+5];
bool a[100000+5];
void dfs(int id,int k,int w,long long sumsum){
    if(id==p[k].k+1)return;
    long long temp;
    for(int i=w;i<p[k].k;i++){
        temp=sumsum*p[k].fen[i];
        if(id&1)ans-=n/temp;
        else ans+=n/temp;
        dfs(id+1,k,i+1,temp);
    }
}//递归实现容斥原理
int main()
{
    int t;
    scanf("%d",&t);
    memset(a,0,sizeof(a));
    a[1]=1;
    for(int i=1;i<100005;i++)
    p[i].k=0;
    for(int i=2;i<=100005;i++){
        if(!a[i]){
            for(int j=i;j<100005;j+=i){
                a[j]=true;
                p[j].fen[p[j].k]=i;
                p[j].k++;
            }
        }
    }//递推进行素因子分解
    while(t--){
        scanf("%d%d",&m,&n);
        long long sum=0;
        for(int i=1;i<=m;i++){
            ans=n;
// cout<<p[i].k<<" ";
            dfs(1,i,0,1);
            sum+=ans;
// cout<<ans<<endl;
        }
        cout<<sum<<endl;
    }
    return 0;
}

你可能感兴趣的:(容斥原理)