https://www.lydsy.com/JudgeOnline/problem.php?id=3505
不算太水的题但也不算太难
首先算出一堆点选三个点的方法数
然后减去三个点一线的方法数
那么问题来了
怎么算呢
其实都是一个套路
找GCD
GCD代表两个点之间在网格上的点的数量加一
然后求区域和
再枚举
左端点然后乘以二
因为左右两边都要算一次下
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=1e3;
ll G[N+10][N+10];
ll A[N+10][N+10];
ll gcd(ll a,ll b){
return a%b==0?b:gcd(b,a%b);
}
int main(){
ll n,m;
cin>>n>>m;
ll x=(n+1)*(m+1);
ll ans=x*(x-1)*(x-2)/6;
ans-=(m+1)*(n+1)*(n)*(n-1)/6;
ans-=(n+1)*(m+1)*(m)*(m-1)/6;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
G[i][j]=gcd(i,j)-1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
A[i][j]=A[i-1][j]+A[i][j-1]-A[i-1][j-1]+G[i][j];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
ans-=A[n+1-i][m+1-j]*2;
cout<<ans<<endl;
}