結果
問題 |
No.1627 三角形の成立
|
ユーザー |
👑 ![]() |
提出日時 | 2025-02-02 16:49:15 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 97 ms / 1,000 ms |
コード長 | 4,180 bytes |
コンパイル時間 | 4,426 ms |
コンパイル使用メモリ | 277,560 KB |
実行使用メモリ | 5,248 KB |
最終ジャッジ日時 | 2025-02-02 16:49:22 |
合計ジャッジ時間 | 6,468 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 22 |
ソースコード
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll MOD = 1000000007; // Modular exponentiation. ll modExp(ll a, ll b, ll mod=MOD) { ll res = 1 % mod; a %= mod; while(b) { if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1; } return res; } // Modular inverse (mod is prime). ll modInv(ll a, ll mod=MOD){ return modExp(a, mod-2, mod); } // Compute binomial coefficient C(x,3) modulo MOD. ll comb3(ll x) { if(x < 3) return 0; ll inv6 = modInv(6); return (((x % MOD) * ((x-1) % MOD)) % MOD * ((x-2) % MOD) % MOD * inv6) % MOD; } // Compute the Möbius function for all numbers up to N. vector<int> mobiusSieve(int N) { vector<int> mu(N+1, 1); vector<int> prime; vector<int> mark(N+1, 0); for (int i = 2; i <= N; i++){ if (!mark[i]){ prime.push_back(i); mu[i] = -1; } for (int p: prime){ if(i*p > N) break; mark[i*p] = 1; if(i % p == 0){ mu[i*p] = 0; break; } else { mu[i*p] = -mu[i]; } } } return mu; } // Main: count triangles in an n x m grid. int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); ll n, m; cin >> n >> m; // Total number of lattice points. ll totalPoints = n * m; // Total ways to choose 3 points. ll totalTrip = comb3(totalPoints); // Count collinear triples on horizontal lines. ll horiz = (n % MOD) * comb3(m) % MOD; // Count collinear triples on vertical lines. ll vert = (m % MOD) * comb3(n) % MOD; // Now count collinear triples on lines with nonzero, non‐infinite slope. // We wish to compute // nonAxis = 2 * sum_{dx=1}^{n-1} sum_{dy=1}^{m-1} (gcd(dx,dy)-1)*(n-dx)*(m-dy). // Change variable: let dx = d*i, dy = d*j with gcd(i,j)=1. // Then set D = min(n-1, m-1) so that d runs 1...D. ll D = min(n - 1, m - 1); ll S_nonAxis = 0; // We need the Möbius function up to D. vector<int> mu = mobiusSieve((int)D); // For each d from 1 to D, let A = floor((n-1)/d) and B = floor((m-1)/d). // Then define: // F(d) = sum_{1<=i<=A, 1<=j<=B, gcd(i,j)=1} (n - d*i)*(m - d*j) // and add (d-1)*F(d) to our total. for (ll d = 1; d <= D; d++){ ll A = (n - 1) / d; ll B = (m - 1) / d; if(A == 0 || B == 0) continue; ll F_val = 0; ll lim = min(A, B); // Möbius inversion: sum over k from 1 to lim. for (ll k = 1; k <= lim; k++){ if(mu[k] == 0) continue; ll A2 = A / k; ll B2 = B / k; // We need: // G = sum_{i=1}^{A2} sum_{j=1}^{B2} (n - d*k*i)*(m - d*k*j) // Because the summand is separable we write: // G = ( n*A2 - d*k * (1+2+...+A2) ) // * ( m*B2 - d*k * (1+2+...+B2) ) ll sum_i = (A2 * (A2 + 1) / 2) % MOD; ll sum_j = (B2 * (B2 + 1) / 2) % MOD; ll part1 = ((n % MOD) * (A2 % MOD)) % MOD; ll t2 = ((d % MOD) * (k % MOD)) % MOD; t2 = (t2 * sum_i) % MOD; part1 = (part1 - t2) % MOD; if(part1 < 0) part1 += MOD; ll part2 = ((m % MOD) * (B2 % MOD)) % MOD; t2 = ((d % MOD) * (k % MOD)) % MOD; t2 = (t2 * sum_j) % MOD; part2 = (part2 - t2) % MOD; if(part2 < 0) part2 += MOD; ll add = (part1 * part2) % MOD; add = (add * mu[k]) % MOD; F_val = (F_val + add) % MOD; if(F_val < 0) F_val += MOD; } ll contrib = ((d - 1) % MOD * F_val) % MOD; S_nonAxis = (S_nonAxis + contrib) % MOD; } ll nonAxis = (2 * S_nonAxis) % MOD; // Total collinear triples are the sum of horizontal, vertical, and non-axis ones. ll collinear = (horiz + vert) % MOD; collinear = (collinear + nonAxis) % MOD; // Answer: non-degenerate triangles. ll ans = (totalTrip - collinear) % MOD; if(ans < 0) ans += MOD; cout << ans % MOD << "\n"; return 0; }