HDU 2841-Visible Trees(容斥)

来源:互联网 发布:飞腾排版软件win7 编辑:程序博客网 时间:2024/06/05 18:22

题目地址:HDU 2841
题意:给出一个m*n的矩阵,从(1,1)开始,一个人站在(0,0)位置,问人可以看到矩阵里的几棵树,要求两棵树和人在同一直线上的时候只能看到一棵。
思路:对于一个点(x,y)只要x与y存在最大公约数g,则可以知道在(x/g,y/g)有一棵树挡起了点(x,y),所以(x,y)是看不到的,因此我们要判断一个点是否能看到,就看它的(x,y)是否存在最大公约数不为1的数,若不存在则可以看到,相反则看不到。而满足最大公约数为1的数就是x 和y 互质,所以我们只要找到矩阵内互质的数之和即可,我们可以固定m,然后从[1,m]找与nn(,nn>=1&&nn<=n)互质的数的和。

#include <stdio.h>#include <math.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <sstream>#include <algorithm>#include <set>#include <queue>#include <stack>#include <map>#include <bitset>using namespace std;typedef __int64 LL;const int inf=0x3f3f3f3f;const double pi= acos(-1.0);const double esp=1e-6;using namespace std;const int Maxn=1e5+10;LL prime[Maxn];LL sprime[Maxn];bitset<Maxn>pri;LL k,cnt;void is_prime(){    pri.set();    for(LL i=2; i<Maxn; i++) {        if(pri[i]) {            prime[k++]=i;            for(LL j=i+i; j<Maxn; j+=i)                pri[j]=0;        }    }}void Divide(LL n){    cnt=0;    LL t=(LL)sqrt(1.0*n);    for(LL i=0; prime[i]<=t; i++) {        if(n%prime[i]==0) {            sprime[cnt++]=prime[i];            while(n%prime[i]==0)                n/=prime[i];        }    }    if(n>1)        sprime[cnt++]=n;}LL Ex(LL n){    LL ans=0;    LL tmp,flag;    LL i,j;    for(i=1;i<(LL)(1<<cnt);i++)    {        tmp=1;        flag=0;        for(j=0;j<cnt;j++)            if(i&((LL)(1<<j))){                flag++;                tmp*=sprime[j];            }        if(flag&1)            ans+=n/tmp;        else            ans-=n/tmp;    }    return ans;}int main(){    int T;    LL m,n;    LL res;    is_prime();    scanf("%d",&T);        while(T--) {          scanf("%lld %lld",&m,&n);          res=0;          for(LL i=1;i<=n;i++){          Divide(i);          res+=(m-Ex(m));          }          printf("%lld\n",res);        }    return 0;}
1 0