BZOJ-3505: [Cqoi2014]数三角形 (容斥原理+排列组合)

3505: [Cqoi2014]数三角形

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1754  Solved: 1082
[Submit][Status][Discuss]

Description

给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。

注意三角形的三点不能共线。

Input

输入一行,包含两个空格分隔的正整数m和n。

Output


输出一个正整数,为所求三角形数量。

Sample Input


2 2

Sample Output

76


数据范围
1<=m,n<=1000

HINT

 

Source

今天下午校内自测爆零了……哇的一声哭了出来QAQ 第一题黑心的秤砣竟然给了道省选题……

苦逼的laj其实20分钟就想到正解了哇,就是要用容斥原理先算出总共的个数包括合法的和不合法的,然后减掉三个点分别在同一行,同一列,还有同一条斜线上的不合法情况……然鹅laj花了2h都没写好统计在同一条斜线上的不合法情况的种类数QAQ,感觉还是陷到瓶颈里了QAQ一直都是想着那条斜线的斜率是小于0的情况,秤砣的算法在写什么鬼东西啊……还是肫的话点醒了laj,为了不与之前斜率一样的情况重复统计,这里首先固定两个点(1,1)和(x,y)然后通过gcd(x-1,y-1)+1算出这条斜线上的整点的个数,减掉固定的两个端点,剩下的就是自由的可行的点,每个点都分别代表着一种不同的情况,因为已经固定的两个点是这三个点之间距离最大的两个点,这个距离一定大于之前算的斜率相同的距离最大的两个点的距离,所以易证不会和之前算的情况重合,对于每个(1,1)到(x,y)的线段,在这个矩阵里总共有(n-x+1)*(m-y+1)条,最后统计一下即可算出答案(因为矩阵的对称性,这只是算出了线段的斜率大于0 的情况,还有对称的斜率小于0的情况,所以斜线上减掉的不合法情况数要乘二)

原来laj离真相就差那么一小步…… _(:зゝ∠)_

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long LL;
 4 const int MAX=1005;
 5 LL n,m,ans;
 6 LL gcd(LL x,LL y){return (y==0?x:gcd(y,x%y));}
 7 LL c(LL x,LL y){
 8     LL i,j,an=1;
 9     for (i=1;i<=y;i++) an*=(x-i+1);
10     for (i=2;i<=y;i++) an/=i;
11     return an;
12 }
13 int main(){
14     freopen ("nmtg.in","r",stdin);
15     freopen ("nmtg.out","w",stdout);
16     LL i,j,k,zt=0;
17     scanf("%lld%lld",&n,&m);n++,m++;
18     ans=c(n*m,3)-(n*c(m,3)+m*c(n,3));
19     for (i=2;i<=n;i++){
20         for (j=2;j<=m;j++){
21             k=gcd(i-1,j-1); k++;
22             if (k<3) continue;
23             ans-=2*(k-2)*(n-i+1)*(m-j+1);
24         }
25     }
26     printf("%lld",ans);
27     return 0;
28 }
未来是什么样,未来会发生什么,谁也不知道。 但是我知道, 起码从今天开始努力, 肯定比从明天开始努力, 要快一天实现梦想。 千里之行,始于足下! ——《那年那兔那些事儿》
原文地址:https://www.cnblogs.com/keximeiruguo/p/7712460.html