点组计数
Time Limit: 20 Sec Memory Limit: 128 MB
Description
平面上摆放着一个nm的点阵(下图所示是一个34的点阵)。Curimit想知道有多少三点组(a,b,c)满足以a,b,c三点共线。这里a,b,c是不同的3个点,其顺序无关紧要。(即(a,b,c)和(b,c,a)被认为是相同的)。由于答案很大,故你只需要输出答案对1,000,000,007的余数就可以了。
有且仅有一行,两个用空格隔开的整数n和m。
Output
有且仅有一行,一个整数,表示三点组的数目对1,000,000,007的余数。(1,000。000。007是质数)
3 4
Sample Output
2 0
HINT
对于100%的数据,1< =N.m< =50000
Main idea
给定一个点阵,问有多少组三点共线。
Solution
其实我也不知道原式怎么来的,我可能只会推式子啊?QAQ
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> using namespace std; typedef long long s64;
const int ONE = 50005; const int MOD = 1000000007; const int Ny6 = 166666668;
int T; int n,m; bool isp[ONE]; int prime[ONE],p_num; int phi[ONE]; s64 Ans;
int get() { int res=1,Q=1; char c; while( (c=getchar())<48 || c>57) if(c=='-')Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res=res*10+c-48; return res*Q; }
void Getphi(int MaxN) { phi[1] = 1; for(int i=2; i<=MaxN; i++) { if(!isp[i]) prime[++p_num] = i, phi[i] = i - 1; for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++) { isp[i * prime[j]] = 1; if(i % prime[j] == 0) { phi[i * prime[j]] = (s64)phi[i] * prime[j] % MOD; break; } phi[i * prime[j]] = (s64)phi[i] * phi[prime[j]] % MOD; } } }
s64 Get(int a,int b,int num) {return (s64)(a+b) * num / 2 %MOD; } s64 Sum(int n,int m) {return ((s64)n*(n-1)/2%MOD) * ((s64)m*(m-1)/2%MOD) % MOD;}
int C(int n) { int res = (s64)n * (n-1) % MOD * (n-2) % MOD; return (s64) res * Ny6 % MOD; }
int main() { Getphi(ONE-1); n=get(); m=get(); if(n > m) swap(n,m); for(int d=1; d<=n; d++) { Ans += phi[d] * Get(n-d,n-(n/d)*d,n/d) % MOD *Get(m-d,m-(m/d)*d,m/d) % MOD; Ans %= MOD; }
Ans = (Ans - Sum(n,m) + MOD) % MOD; Ans = Ans*2%MOD + (s64)C(n)*m%MOD + (s64)C(m)*n%MOD; Ans %= MOD;
printf("%lld",Ans); }
|