码迷,mamicode.com
首页 > 其他好文 > 详细

[CQOI2014]数三角形

时间:2019-02-11 20:09:29      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:show   lin   两种   题意   mat   new   print   long   方案   

传送门

题意:给定一个nxm的网格,计算三点都在格点上的三角形共有多少个?注意三角形的三点不能共线.

分析:nxm的网格有tot=(n+1)*(m+1)个格点,暴力算出所有方案数\(C_{tot}^3\),然后减去平行于x轴和y轴的共线三角形\((n+1)*C_{m+1}^3\)\((m+1)*C_{n+1}^3\),最后减去倾斜直线上的共线三角形.

这个比较麻烦,我先直接给出式子,然后再来具体分析,因为懒得画图(其实是不会),所以就只能耐心地口胡\(2*(gcd(i,j)-1)*(n+1-i)*(m+1-j)\)

乘2:矩形具有对称性,所以倾斜直线也是对称的(就是说把倾斜直线看作一种是自左上往右下,另一种是自右上往左下,这两种情况是相同的,所以我们下面可以只讨论一种情况)

乘gcd(i,j)-1:首先要知道一个结论,对于点(a,b)和(x,y)连成的线段而言(其中a>x,b>y),在它们中间有gcd(a-x,b-y)-1个整点(自己画几个图就能发现这个规律了),然后我们不妨以左上角(0,0)点为枚举矩形的左上角顶点,所以我们只需要枚举右下角顶点(i,j)就可以了.根据结论这两个点连成的线段中间有gcd(i-0,j-0)-1个格点.

对于\(n*m\)的网格而言,像上述那样枚举矩形的话,一共有(n+1-i)*(m+1-j)个矩形(这里不明白也画几个图吧)

int gcd(int x,int y){
    if(y==0)return x;
    return gcd(y,x%y); 
}
int main(){
    int m=read(),n=read();
    m++;n++;//为了方便,这里直接都+1了
    int tot=m*n;
    long long ans=1LL*tot*(tot-1)*(tot-2)/6-1LL*m*n*(n-1)*(n-2)/6-1LL*n*m*(m-1)*(m-2)/6;
    for(int i=1;i<n;i++)
        for(int j=1;j<m;j++)
            ans-=1LL*2*(gcd(i,j)-1)*1LL*(n-i)*(m-j); 
    printf("%lld\n",ans);
    return 0;
}

[CQOI2014]数三角形

标签:show   lin   两种   题意   mat   new   print   long   方案   

原文地址:https://www.cnblogs.com/PPXppx/p/10362950.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!