分析
总方案就是(C(n*m,3)),考虑减掉不合法的方案,
横向(n*C(m,3)),纵向(m*C(n,3))再减去斜着的,
对于((x_1,y_1)(x_2,y_2),x_1<x_2,y_1<y_2)上有(gcd(x_2-x_1,y_2-y_1)-1)个整点
那可以枚举((i=x_2-x_1,j=y_2-y_1)),由于这两个点有可能会满足(x_1<x_2,y_1>y_2),所以方案数要乘上2
答案就是
[C(n*m,3)-n*C(m,3)-m*C(n,3)-sum_{i=1}^{n-1}sum_{j=1}^{m-1}2*(n-i)*(m-j)*(gcd(i,j)-1)
]
记忆化两数gcd就可以做到(O(nm))了,当然推式子做到(O(min(n,m)))也可以
代码
#include <cstdio>
#define rr register
int n,m,Gcd[1001][1001]; long long ans;
inline signed gcd(int x,int y){
if (Gcd[x][y]) return Gcd[x][y];
if (!y) return x; else return gcd(y,x%y);
}
signed main(){
scanf("%d%d",&n,&m),++n,++m;
ans=1ll*n*m*(n*m-1)*(n*m-2)/6;
ans-=1ll*m*n*((n-1)*(n-2)/2+(m-1)*(m-2)/2)/3;
for (rr int i=1;i<n;++i)
for (rr int j=1;j<m;++j){
Gcd[i][j]=gcd(i,j);
ans-=2ll*(n-i)*(m-j)*(Gcd[i][j]-1);
}
return !printf("%lld",ans);
}