给你n * m 的的矩形方格, 也即有(n + 1) * (m + 1) 个点, 然后问可以找到做少个三角形。
n比较大显然是不能暴力枚举的, 然后想dp递推也发现太复杂了,,于是想逆向求解,比赛的时候想的是枚举斜率, 然后判断当前斜率下右多少点共线, 再考虑平移, 可是还是不对,,跟ac代码比了很多样例都是没问题的。。醉了。
然后Ac代码的解题方式是, 枚举每条直线的一个端点, 另一个端点是0,0,然后这条直线上,选两个端点的情况下, 不符合条件的方法数就是__gcd(i, j) - 1。然后再考虑平移然后再乘二,再用总的方法数减掉就可以了。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cctype>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls id<<1,l,mid
#define rs id<<1|1,mid+1,r
#define OFF(x) memset(x,-1,sizeof x)
#define CLR(x) memset(x,0,sizeof x)
#define MEM(x) memset(x,0x3f,sizeof x)
typedef long long ull ;
typedef pair<int,int> pii ;
const int maxn = 1e5+50 ;
const int inf = 0x3f3f3f3f ;
const int MOD = 1e9+7 ;
ull a[1055];
void init() {
a[2] = 0;
for (int i = 3; i <= 1005; i++) a[i] = a[i - 1] + i * (i - 1) * (i - 2) / 6;
// cout << a[1000] << "\n" ;
}
int main () {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int n,m;init();
while (~scanf("%d%d", &n, &m)) {
ull tmp = 0;
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= m; j++) {
tmp += 1LL * (__gcd(i,j) - 1) * (n - i + 1) * (m - j + 1) * 2;
}
}
tmp += 1LL * (m + 1) * (n + 1) * (n - 1) * n / 6;
tmp += 1LL * (n + 1) * (m + 1) * (m - 1) * m / 6;
ull d = (m + 1) * (n + 1);
ull ans = d * (d - 1) * (d - 2) / 6;
cout << ans - tmp << "\n" ;
}
return 0;
}