hdu 2841 Visible Trees 寻找互质 容斥定理

题意是农夫站在(0,0) 在(1,1)-(m,n)的矩形的每个点上种满树。

前面的数会挡住后面的树。

农夫能看见多少树。

这题就是连接农夫与任意一棵树,有多少种不同的斜率即能看到多少树,但是直接暴力做肯定超时。

如果(x,y)互质,即是新树,否则已经有过这棵树。

那么x从1-m 对于每一个x 寻找y在1-n之间又多少个与x互质的数。

这里用到容斥定理,寻找不互质的,总数相减。

例如2 2

1 2与1互质  斜率有1/1 2/1

1 与2互质  斜率有1/2

总数为3

#include<stdio.h>
#include<string.h>
int pr[444],num,id[444],a[1111];
__int64 x,y;
__int64 ans;
int cnt;
void get_s()
{
	memset(id,0,sizeof(id));
	int i;
	num=0;
	int j;
	for(i=2;i<444;i++)
	{
		if(id[i]==0)
		{
			num++;
			pr[num]=i;
		}
		for(j=1;j<=num&&pr[j]*i<444;j++)
		{
			id[pr[j]*i]=1;
			if(i%pr[j]==0) break;
		}
	}
}

void dfs(int id,__int64 lcm,int num,__int64 x)
{
	lcm=lcm*a[id]; //lcm是最小公倍数,因为是不同的质因数,直接相乘。 
	if(num&1)
	ans+=x/lcm;
	else 
	ans-=x/lcm;
	for(int i=id+1;i<=cnt;i++)
	dfs(i,lcm,num+1,x);
}
int main()
{
    __int64 d,putt;
	get_s();
	int i,zz=1,j,k;
	int T,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%I64d%I64d",&x,&y);
		if(x>y)
		{
			d=x;
			x=y;
			y=d;
		}
		putt=y;
		for(i=2;i<=x;i++)
		{
			d=i;
			cnt=0;
			ans=0;
			for(j=1;j<=num;j++)   //获得质因数 
			{
				if(d==1) break;
				if(d%pr[j]==0)
				{
					cnt++;
					a[cnt]=pr[j];
					while(d%pr[j]==0)
					d/=pr[j];
				}
				
			}
			if(d!=1)           
				{
					cnt++;
					a[cnt]=d;
				}
				for(k=1;k<=cnt;k++)
				dfs(k,1,1,y);
				ans=y-ans;         //把ans从不互质的变成互质的 
				putt+=ans;
		}
		printf("%I64d\n",putt);
	}
	return 0;
}


你可能感兴趣的:(hdu 2841 Visible Trees 寻找互质 容斥定理)