結果
| 問題 |
No.1627 三角形の成立
|
| コンテスト | |
| ユーザー |
👑 null
|
| 提出日時 | 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;
}
null