#最大公约数,容斥#洛谷 3166 [CQOI2014]数三角形

题目


分析

总方案就是(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);
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13523948.html