hdoj Lattice triangle 4483 (欧拉函数&&容斥)

Lattice triangle

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 129 Accepted Submission(s): 87


Problem Description
  A lattice point is a point with integer coordinates. A lattice triangle is a triangle with all vertices lattice points.
  Now your task is to calculate how many lattice triangles are there, under the condition that each of its vertex (x, y) satisfies 0 <= x <= N and 0 <= y <= N.
  We say two triangles are different if and only if they have at least one different vertex.

Input
  There is an integer T (1 <= T <= 1000) in the first line, which indicates there are T test cases in total.
  For each test case, there is only one integer N (1 <= N <= 100000) which has the same meaning as above.
There are at most 10 test cases that satisfy N > 1000.

Output
  For each test case, you should output the correct answer of the above task in one line.
  Because the answer may be very large, you should just output the remainder of it divided by 1000000007 instead.

Sample Input
  
  
3 1 2 100000

Sample Output
  
  
4 76 157621156
Hint
For sample 2: We can get the correct answer by calculating C(9, 3) - 8.
题意:在n*n的网格内找到3个格点,使它能构成三角形,问能构成多少个三角形? 方法:     总共有t=(n+1)*(n+1)个格点,所以令n++     1.任取三个点ans=c(t,3)     2.去掉在一条直线三的三个点ans=ans-c(n,3)*n*2     3.还要去掉在一条斜线上的三个点:         对于长宽为i,j的矩形,对角线上有gcd(i,j)-1个格点(不包括两端点),这样我们就能枚举矩形,去掉不能构成三角形的三个点         则要去掉的方案数为∑∑(n-i)*(n-j)*(gcd(i,j)-1);         本题n太大,还要优化成O(n)复杂度才可以     优化:         令i=a*k,j=b*k,其中k为(i,j)的最大公约数         则条件3的方案数为sum=∑∑∑(n-a*k)*(n-b*k)*(k-1)=∑∑∑(n*n-(a+b)*n*k+a*b*k*k)*(k-1)             =∑[k](k-1)*(n*n*∑∑1+n*k*∑∑(a*b)+k*k*∑∑(a*b))                  其中i,j<n,所以a,b<=(n-1)/k=m;         phi[i]为欧拉函数,a,b<=m中,∑∑=a,b两两互质的个数=1+(phi[2]+phi[3]+...+phi[m])*2         phi[i]的个数只是说a<b,b=i时有多少个,还有a>b,所以要乘以2,除了a=b=1以外                  定理:如果gcd(a,b)==1,则gcd(a,a-b)==1。所以phi[i]个与i互质的数种,成对出现,每对之和为i         所以∑∑(a+b)=∑(phi[i]/2*i+phi[i])*2                  由上述定理可以知道:phi[i]个互质的数与i的乘积之和为i*(x1+x2+..xm)=i*ph[i]/2*i;         所以∑∑(a*b)=∑(phi[i]*i*i/2)*2
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
const ll M=1000000007;
ll x[N],y[N],z[N];
ll a[N];
ll n;
void eular()
{
	ll i,j,k;
	memset(a,0,sizeof(a));
	a[1]=1;
	for(i=2;i<N;i++)
	{
		if(!a[i])
		{
			for(j=i;j<=N;j+=i)
			{
				if(!a[j])
					a[j]=j;
				a[j]=a[j]/i*(i-1);
			}
		}
	}
	x[1]=z[1]=1;y[1]=2;
	for(i=2;i<N;i++)
	{
		x[i]=(x[i-1]+a[i]*2)%M;
		y[i]=(y[i-1]+a[i]*i*3)%M;
		z[i]=(z[i-1]+a[i]*i%M*i)%M;
	}
}
int main()
{
	eular();
	int t;
	ll m,i,k,mm,ans;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lld",&n);
		n++;
		k=(n*n)%M;
		m=M*6;
		ans=k*(k-1)%m*(k-2)%m/6;
		ans-=k*(n-1)%m*(n-2)*2%m/6;
		k=0;
		for(i=2;i<n;i++)
		{
			mm=(n-1)/i;
			k=(k+(i-1)*(x[mm]*n%M*n%M-n*i%M*y[mm]%M+i%M*i%M*z[mm]%M))%M;
		}
		ans-=k*2;
		printf("%lld\n",(ans%M+M)%M);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值