UVa 1393 / LA 3720 Highways
一开始以为要用欧拉函数解决,看了半天,发现怎么套都套不上去,只好换个角度思考,由于是递推专题,就用递推的思路尝试一下,如果n行m列的所有道路都已经建好。现在新添加一行,即第n+1行,会有哪些道路需要建设?
先看第n+1行的第一个点a,再选择一个非同行同列的点b,若a与b之间没有道路,需要满足哪些条件?
a与b之间没有道路就必须满足a与b之间的道路没有经过其它点,即a与b之间的横纵坐标之差互质。想到这就自以为解决问题了。
后来发现互质只是条件之一,若有另外一点c与a的横坐标之差和纵坐标之差都是b的两倍,那么a与b的道路就已经存在。所以完整的条件是a与b互质且没有任何一点与a的横坐标之差和纵坐标之差都是b的两倍。
在代码实现时还需要一些小技巧来加速。详见代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 333; 7 int c[maxn][maxn]; 8 9 int gcd(int a, int b) 10 { 11 return b ? gcd(b, a % b) : a; 12 } 13 14 void init() 15 { 16 int i, j, k, n = 300; 17 memset(c, 0, sizeof(c)); 18 for(i = 1; i <= n; i ++) 19 for(j = 1; j <= n; j ++) 20 { 21 k = gcd(i, j); 22 if(k == 1) 23 c[i][j] = 1; 24 else if(k == 2) 25 c[i][j] = -1; 26 } 27 28 for(i = 1; i <= n; i ++) 29 for(j = 2; j <= n; j ++) 30 c[i][j] += c[i][j - 1]; 31 32 for(i = 2; i <= n; i ++) 33 for(j = 1; j <= n; j ++) 34 c[i][j] += c[i - 1][j]; 35 } 36 37 int main() 38 { 39 int n, m, i, j, ans; 40 init(); 41 for(;scanf("%d%d", &n, &m), n + m;) 42 { 43 if(n > m) 44 swap(n, m); 45 ans = 0; 46 for(i = 1; i < n; i ++) 47 for(j = 0; j < m; j ++) 48 ans += c[i][m - 1 - j] + c[i][j]; 49 printf("%d\n", ans); 50 } 51 return 0; 52 }