这个题一看就可以离散、
利用容斥,所以可以用组合数算出所有的三点组合,,再减去在一条线上的点的组合
垂直和水平的好算,斜的就比较繁琐
首先我猜了一个错误的结论:所有直线都可以用左上边界和右下边界的点连接平移而成
然后反例一大堆、
于是又提出了一个错误的结论:原图扩大2倍
然后反例还是一大堆
最终得出结论:原图扩大为原来的平方、、
这次对了,但复杂度不对
但这说明了,所有的直线会受制于边长的限制,边长越小,直线越少
于是就可以想到,从左上角到任意一个点的直线一定包含所有直线。因为如果不从左上角开始,选择的空间一定不会比原来更大
然后就看这个矩形中有多少这样的直线,,来计算对答案的贡献
注意:这样遍历所有同样的直线 会被分成若干小段,所以每次就只需要考虑新加入点(右端点)的贡献
码:
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int gcd(int a,int b)
{
if(!b)return a;
return gcd(b,a%b);
}
ll n,m,ans,i,j;
int main()
{
scanf("%lld%lld",&n,&m);
ans=(n+1)*(m+1)*((n+1)*(m+1)-1)*((n+1)*(m+1)-2)/6;
ans-=((m+1)*m*(m-1)*(n+1)+(n+1)*n*(n-1)*(m+1))/6;
for(i=0;i<=n;i++)
for(j=0;j<=m;j++)
{if(i==0||j==0)continue;
ans-=1ll*(gcd(i,j)-1)*(m+1-j)*(n+1-i)*2;
}
printf("%lld",ans);
}