#最大公约数,容斥#洛谷 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);
}
posted @ 2020-08-18 15:48  lemondinosaur  阅读(95)  评论(0编辑  收藏  举报