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.
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.
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.
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 157621156HintFor 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; }