なるほど…。
https://yukicoder.me/problems/no/1627
問題
2次元座標上、N*W個グリッド状に格子点がある。
ここから3点を選んで三角形を作ったとき、面積が正となるのは何通りか。
解法
全点から3点の選びかたから、面積が0、すなわち3点が一直線上になるものを引こう。
まず、3点がX軸またはY軸に平行なケースは容易なので先に除いておく。
一直線に並ぶ3点中、両端のX座標の差とY座標の差のGCDがgの時、その間に点を置いた時3点が一直線に並ぶケースはg-1通りである。
そこで、GCDがgとなるような両端の選び方を数え上げよう。
これは、「両端のX座標の差とY座標の差がいずれもgの倍数の時」の組み合わせを求めた後、約数包除の要領で「GCDがg」のケースを求めればよい。
ll H,W; const ll mo=1000000007; ll modpow(ll a, ll n = mo-2) { ll r=1;a%=mo; while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1; return r; } ll A[303030],B[303030],C[303030]; void solve() { int i,j,k,l,r,x,y; string s; cin>>H>>W; ll all=1LL*H*W%mo; ll ret=all*(all-1)%mo*(all-2)%mo*modpow(6)%mo; ret-=W*H%mo*(H-1)%mo*(H-2)%mo*modpow(6); ret-=H*W%mo*(W-1)%mo*(W-2)%mo*modpow(6); ret=(ret%mo+mo)%mo; for(i=1;i<W;i++) A[i]=(W-i)%mo; for(i=1;i<H;i++) B[i]=(H-i)%mo; for(i=1;i<=300000;i++) { ll SA=0; ll SB=0; for(x=i;x<=300000;x+=i) { SA+=A[x]; SB+=B[x]; } SA%=mo; SB%=mo; C[i]=2*SA*SB%mo; } for(i=300000;i>=1;i--) { for(x=2*i;x<=300000;x+=i) { C[i]-=C[x]; } C[i]=(C[i]%mo+mo)%mo; ret-=(i-1)*C[i]%mo%mo; } cout<<(ret%mo+mo)%mo<<endl; }
まとめ
シンプルん問題設定で良いね。