bzoj 3505 数三角形 - 组合数学
2017-07-06 09:53
447 查看
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
Sample Output
Hint
不难得到一个思路。最终的答案 = 任选3点的方案数 - 三点共线的方案数。
前者很好求直接组合数就好了。后者可以枚举线段两端点,然后计算第三个点在这个线段上(不含端点)的方案数,这要用到在网格图中一个神奇的结论,两个格点点的连线穿过的格点数等于这两点的横纵坐标之差的最大公约数减一,至于它的证明可以用相似再加一点数论的东西。但是枚举任意两点会超时。但发现很多地方其实这个横纵坐标的差是相等的,所以直接枚举这个横纵坐标之差,然后乘法乘一乘就好了。
注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
2 2
Sample Output
76
Hint
数据范围 1<=m,n<=1000
不难得到一个思路。最终的答案 = 任选3点的方案数 - 三点共线的方案数。
前者很好求直接组合数就好了。后者可以枚举线段两端点,然后计算第三个点在这个线段上(不含端点)的方案数,这要用到在网格图中一个神奇的结论,两个格点点的连线穿过的格点数等于这两点的横纵坐标之差的最大公约数减一,至于它的证明可以用相似再加一点数论的东西。但是枚举任意两点会超时。但发现很多地方其实这个横纵坐标的差是相等的,所以直接枚举这个横纵坐标之差,然后乘法乘一乘就好了。
Code
/** * bzoj * Problem#3505 * Accepted * Time:344ms * Memory:1288k */ #include<iostream> #include<cstdio> #include<ctime> #include<cctype> #include<cstring> #include<cstdlib> #include<fstream> #include<sstream> #include<algorithm> #include<map> #include<set> #include<stack> #include<queue> #include<vector> #include<stack> #ifndef WIN32 #define Auto "%lld" #else #define Auto "%I64d" #endif using namespace std; typedef bool boolean; const signed int inf = (signed)((1u << 31) - 1); #define smin(a, b) a = min(a, b) #define smax(a, b) a = max(a, b) #define max3(a, b, c) max(a, max(b, c)) #define min3(a, b, c) min(a, min(b, c)) template<typename T> inline boolean readInteger(T& u){ char x; int aFlag = 1; while(!isdigit((x = getchar())) && x != '-' && x != -1); if(x == -1) { ungetc(x, stdin); return false; } if(x == '-'){ x = getchar(); aFlag = -1; } for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); ungetc(x, stdin); u *= aFlag; return true; } template<typename T> T gcd(T a, T b) { if(!b) return a; return gcd(b, a % b); } int n, m; int pro; long long res; inline void init() { readInteger(n); readInteger(m); pro = (n + 1) * (m + 1); res = pro * 1LL * (pro - 1) * (pro - 2) / 6; } inline void solve() { for(int i = 0; i <= n; i++) { for(int j = 0; j <= m; j++) { if(i == 0 && j == 0) continue; long long t = (gcd(i, j) - 1LL) * (n - i + 1) * (m - j + 1); if(!i || !j) res -= t; else res -= (t << 1); } } printf(Auto, res); } int main() { init(); solve(); return 0; }
相关文章推荐
- bzoj 3505: [Cqoi2014]数三角形 排列组合+数学
- [bzoj3505][CQOI2014]数三角形_组合数学
- BZOJ 3505 [Cqoi2014]数三角形(组合数学)
- BZOJ 3505: [Cqoi2014]数三角形|组合数学
- bzoj 3505: [Cqoi2014]数三角形 组合数学
- 【组合数学】BZOJ3505 [Cqoi2014]数三角形
- [BZOJ3505][Cqoi2014]数三角形(组合数学+gcd)
- BZOJ 3505 CQOI2014 数三角形 组合数学
- 【bzoj3505】 CQOI2014数三角形 数学
- BZOJ 3505: [Cqoi2014]数三角形( 组合数 )
- 3505: [Cqoi2014]数三角形 组合数学
- BZOJ 3505: [Cqoi2014]数三角形 [组合计数]
- BZOJ 3505 CQOI 2014 数三角形 数学
- [组合计数] BZOJ 3505 [Cqoi2014]数三角形
- bzoj 3505 数三角形 组合数 解题报告
- bzoj 3505: [Cqoi2014]数三角形 数学
- 【bzoj3505】【CQOI2014】【数三角形】【组合数学】
- 【排列组合】bzoj3505 [Cqoi2014]数三角形
- bzoj 3505 [Cqoi2014]数三角形 组合
- BZOJ 3505 浅谈组合数学在图形区域分割问题的应用