HDU2841 Visible Trees (容斥原理)

bigbigship發表於2014-10-29

題目連結http://acm.hdu.edu.cn/showproblem.php?pid=2841

題意: 

一個人在(0,0)點,然後前面有一個m*n的格子 ,每個格子的節點上有一棵樹,問這個人站在原地能看到多少棵樹

如果兩棵樹在一條直線上那麼只能看到最前面的一棵樹。

分析

如果一個數的座標為(a,b),那麼座標為(a*k,b*k)的都不能看見,如果a,b有公因子c那麼我們肯定只能看到(a/c,b/c);

因此我們得出結論,能看到的樹的橫縱座標一定互質。那麼我們就可以把問題轉化為,從[1,n]有多少個數與m裡的數互質。

那麼只用把[1,n]裡的數都素因子分解了,然後容斥一下就搞定了。

程式碼如下

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 100010;
typedef long long LL;

int Prim[maxn],num[maxn][20];
void init()
{
    int i,j;
    memset(Prim,0,sizeof(Prim));
    for(i=1; i<=100000; i++) num[i][0]=0;
    for(i=2; i<=100000; i++)
    if(Prim[i]==0)
    {
        num[i][1]=i;
        num[i][0]++;
        for(j=i*2; j<=100000; j+=i)
        {
            num[j][++num[j][0]]=i;
            Prim[j]=1;
        }
    }
}

LL dfs(int id,int b,int now)//求不大於b的數中,與now不互質的數的個數;
{
    LL ans=0;
    for(int i=id;i<=num[now][0];i++)
        ans+=b/num[now][i]-dfs(i+1,b/num[now][i],now);
    return ans;
}

int main()
{
    int m,n,t;
    cin>>t;
    while(t--){
        cin>>m>>n;
        init();
        long long sum=0;
        for(int i=2;i<=m;i++)
            sum+=n-dfs(1,n,i);
        printf("%I64d\n",sum+n);
    }
    return 0;
}



相關文章