bzoj 3505: [Cqoi2014]数三角形 排列组合+数学

来源:互联网 发布:快速建模软件 编辑:程序博客网 时间:2024/05/07 23:44

题意

给出一个n*m的网格图(也就是(n*1)*(m*1)个点),问有多少个在格点上的不同的三角形。
n,m<=1000

分析

看了题解才会做。

很显然答案就是任意选三个点的方案数减去三点在同一直线上的方案数。
首先有一个结论,就是在(a,b)和(x,y)连成的线段(a>x,b>y)上有gcd(a-x,b-y)+1个格点,假设以这两个端点为两个端点,第三个端点在这条线段上,那么显然有gcd(a-x,b-y)-1这么多种方案。
如果暴力的话复杂度就是O(n2m2)
我们考虑把这条线段平移,使其一个端点为原点,那么与它长度相同的线段数量即为(n-i+1)*(m-i+1),那么枚举每一个点,然后统计答案即可。

一开始找了半天找不到错后来发现是gcd打错了。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define ll long longusing namespace std;int gcd(int x,int y){    if (x%y==0) return y;    else return gcd(y,x%y);}int main(){    int n,m;    scanf("%d%d",&n,&m);    int w=(n+1)*(m+1);    ll ans=(ll)w*(w-1)*(w-2)/6;    for (int i=2;i<=n;i++)        ans-=(ll)(i-1)*(n-i+1)*(m+1);    for (int j=2;j<=m;j++)        ans-=(ll)(j-1)*(n+1)*(m-j+1);    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)        {            int s=gcd(i,j)-1;            ans-=(ll)s*(n-i+1)*(m-j+1)*2;        }    printf("%lld",ans);    return 0;}
0 0
原创粉丝点击