其他分享
首页 > 其他分享> > BZOJ-3505 [Cqoi2014]数三角形(计数+容斥)

BZOJ-3505 [Cqoi2014]数三角形(计数+容斥)

作者:互联网

题目描述

  给定一个 \(n\times m(1\leq n,m\leq 1000)\) 的网格,计算三点都在格点上的三角形共有多少个。注意三角形的三点不能共线。

分析

  一共有 \((n+1)(m+1)\) 个点,所以任选三个点的总方案数为 \(\dbinom{(n+1)(m+1)}{3}\)。

  三点共线的方案数等于横着的 \(+\) 竖着的 \(+\) 斜着的。

  横着的方案数有 \((n+1)·\dbinom{m+1}{3}\),竖着的方案数有 \((m+1)·\dbinom{n+1}{3}\)。

  考虑如何计算斜着的方案数,斜着的直线按斜率正负分为两种,而且两种方案数相同,所以只需要算出斜率为正的方案数再乘 \(2\) 即可。

  假设线段 \(AB\) 平行于 \(x\) 轴,长度为 \(i\),线段 \(BC\) 平行于 \(y\) 轴,长度为 \(j\),则线段 \(AC\) 上的整点数量为 \(\gcd(i,j)+1\)。

  枚举 \(A\)、\(B\) 两点的横坐标之差 \(i\),纵坐标之差 \(j\),则两点连线上的整点数量为 \(\gcd(i,j)+1\)(不算两端点的话数量为 \(\gcd(i,j)-1\))。对于每组横坐标之差为 \(i\),纵坐标之差为 \(j\) 的点对,先取两端点,再在两端点之间的 \(\gcd(i,j)-1\) 个点中任选一个作为第三个点,方案数为 \(\gcd(i,j)-1\)。

  像这样横坐标之差为 \(i\),纵坐标之差为 \(j\) 的点对共有 \((n-i-1)(m-j+1)\) 个,则斜着的方案数为:

\[ans=\sum_{i=1}^{n}\sum_{j=1}^{m}(n-i+1)(m-j+1)(\gcd(i,j)-1) \]

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long C[1000100][4];
void init()
{
    C[0][0]=1;
    for(int i=1;i<=(n+1)*(m+1);i++)
    {
        C[i][0]=1;
        for(int j=1;j<=3;j++)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
}
int main()
{
    cin>>n>>m;
    init();
    long long ans=C[(n+1)*(m+1)][3]-(n+1)*C[(m+1)][3]-(m+1)*C[(n+1)][3];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ans=ans-2*(n-i+1)*(m-j+1)*(__gcd(i,j)-1);
    cout<<ans<<endl;
    return 0;
}

标签:方案,gcd,int,容斥,之差,long,3505,Cqoi2014,dbinom
来源: https://www.cnblogs.com/DestinHistoire/p/13960204.html