首页 > 代码库 > BZOJ 3505 [Cqoi2014]数三角形
BZOJ 3505 [Cqoi2014]数三角形
3505: [Cqoi2014]数三角形
Description
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
2 2
Sample Output
76
HINT
数据范围
1<=m,n<=1000
这肯定是很典型的排列组合水题。先n++,m++,再C(n*m,3),最后减去三点共线的特例。
横的,竖的,很好算,C(n,3)*m+C(m,3)。但是斜的,需要想一想。
在(a,b) (x,y)两点构成的线段上有gcd(a-x,b-y)-1个整点(a>x,b>y),这显然成立。斜的即有两点,△x与△y均大于0,在他们之间有gcd(△x,△y)-1个整点,而这种情况有2*(n-△x)*(m-△y)种。以O(n^2)的效率减去就是了。
1 /************************************************************** 2 Problem: 3505 3 User: Doggu 4 Language: C++ 5 Result: Accepted 6 Time:660 ms 7 Memory:820 kb 8 ****************************************************************/ 9 10 #include <cstdio>11 #include <algorithm>12 long long n, m, x, ans;13 inline long long gcd(long long a,long long b) {return b==0?a:gcd(b,a%b);}14 inline long long C(long long p) {return p*(p-1)*(p-2)/6;}15 int main() {16 scanf("%lld%lld",&n,&m);n++;m++;x=std::min(n,m);17 ans=C(n*m)-C(n)*m-C(m)*n;18 for( int i = 1; i < n; i++ ) for( int j = 1; j < m; j++ ) ans-=(gcd(i,j)-1)*2*(n-i)*(m-j);19 printf("%lld\n",ans);20 return 0;21 }22
但是,居然发现,若把gcd记忆化,效率将大大提高。
1 /************************************************************** 2 Problem: 3505 3 User: Doggu 4 Language: C++ 5 Result: Accepted 6 Time:292 ms 7 Memory:8792 kb 8 ****************************************************************/ 9 10 #include <cstdio>11 #include <algorithm>12 long long n, m, x, ans, g[1010][1010];13 inline long long gcd(long long a,long long b) {if(g[a][b]) return g[a][b];return g[a][b]=b==0?a:gcd(b,a%b);}14 inline long long C(long long p) {return p*(p-1)*(p-2)/6;}15 int main() {16 scanf("%lld%lld",&n,&m);n++;m++;x=std::min(n,m);17 ans=C(n*m)-C(n)*m-C(m)*n;18 for( int i = 1; i < n; i++ ) for( int j = 1; j < m; j++ ) ans-=(gcd(i,j)-1)*2*(n-i)*(m-j);19 printf("%lld\n",ans);20 return 0;21 }22
BZOJ 3505 [Cqoi2014]数三角形
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。