您的位置:首页 > 其它

HDU 2841-Visible Trees(容斥)

2015-08-24 20:59 489 查看
题目地址: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: