UVa 1393 / LA 3720 Highways

一开始以为要用欧拉函数解决,看了半天,发现怎么套都套不上去,只好换个角度思考,由于是递推专题,就用递推的思路尝试一下,如果nm列的所有道路都已经建好。现在新添加一行,即第n+1行,会有哪些道路需要建设?

先看第n+1行的第一个点a,再选择一个非同行同列的点b,若ab之间没有道路,需要满足哪些条件?

ab之间没有道路就必须满足ab之间的道路没有经过其它点,即ab之间的横纵坐标之差互质。想到这就自以为解决问题了。

 

后来发现互质只是条件之一,若有另外一点ca的横坐标之差和纵坐标之差都是b的两倍,那么ab的道路就已经存在。所以完整的条件是ab互质且没有任何一点与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
", ans);
50     }
51     return 0;
52 }
原文地址:https://www.cnblogs.com/xchaos/p/3293113.html