题意:
给出一个n行m列的点阵,求共有多少条非水平非竖直线至少经过其中两点。
分析:
首先说紫书上的思路,编程较简单且容易理解。由于对称性,所以只统计“\”这种线型的,最后乘2即是答案。
枚举斜线包围盒的大小,如果盒子的长宽ab互质,则是可以的。这种盒子共有(m-a)(n-b)个,但要减去其中重复的。如果有一个长宽为2a和2b的大盒子,则计数右下角的小盒子的同时,左上角的小盒子会重复,所以要减去重复的盒子的个数c = max(0, m-2a) * max(0, n-2b)
最后gcd(a, b)的值是要预处理的
1 #include <cstdio> 2 #include <algorithm> 3 4 const int maxn = 300; 5 int gcd[maxn+10][maxn+10]; 6 7 int GCD(int a, int b) 8 { 9 return b == 0 ? a : GCD(b, a%b); 10 } 11 12 int main() 13 { 14 for(int i = 1; i <= maxn; ++i) 15 for(int j = 1; j <= i; ++j) 16 gcd[i][j] = gcd[j][i] = GCD(i, j); 17 18 int n, m; 19 while(scanf("%d%d", &n, &m) == 2 && n) 20 { 21 int ans = 0; 22 for(int a = 1; a <= n; ++a) 23 for(int b = 1; b <= m; ++b) 24 if(gcd[a][b] == 1) 25 { 26 int c = std::max(0, n-a*2) * std::max(0, m-b*2); 27 ans += (n-a)*(m-b) - c; 28 } 29 30 printf("%d\n", ans * 2); 31 } 32 33 return 0; 34 }
代码君
解法二:
解法转自UVA 1393 - Highways (容斥原理计数)
dp(i, j)表示在长宽为ij的盒子中,从左上角最多能连多少条不重复的直线。
可以根据容斥原理递推dp(i, j) = dp(i-1, j) + dp(i, j-1) - dp(i-1, j-1) + (gcd(i, j) = 1) (因为盒子两边长互质的时候,才能连出一条新边出来)
最后答案ans递推的形式也是一样的,但重复的连线是那些缩小两倍后仍存在的直线
ans(i, j) = ans(i-1, j) + ans(i, j-1) - ans(i-1, j-1) + dp(i, j) - dp(i/2, j/2)
最后代码中,本想着只计算一半答案会快一点,结果排名21,登榜失败。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int maxn = 300; 5 int dp[maxn+1][maxn+1], ans[maxn+1][maxn+1]; 6 7 int gcd(int a, int b) 8 { 9 return b == 0 ? a : gcd(b, a%b); 10 } 11 12 void Init() 13 { 14 for(int i = 1; i <= maxn; ++i) 15 for(int j = 1; j <= i; ++j) 16 { 17 if(i == j) dp[i][j] = dp[i][j-1] * 2 - dp[i-1][j-1] + (gcd(i, j) == 1); 18 else dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + (gcd(i, j) == 1); 19 } 20 21 for(int i = 1; i <= maxn; ++i) 22 for(int j = 1; j <= i; ++j) 23 { 24 if(i == j) ans[i][j] = ans[i][j-1] * 2 - ans[i-1][j-1] + dp[i][j] - dp[i/2][j/2]; 25 else ans[i][j] = ans[i][j-1] + ans[i-1][j] - ans[i-1][j-1] + dp[i][j] - dp[i/2][j/2]; 26 } 27 } 28 29 int main() 30 { 31 Init(); 32 int n, m; 33 while(scanf("%d%d", &n, &m) == 2 && n) 34 { 35 if(n < m) std::swap(n, m); 36 printf("%d\n", ans[n-1][m-1]*2); 37 } 38 39 return 0; 40 }
代码君
时间: 2024-11-05 04:00:15