uva1393 Highways

留坑(p.339) 已填(膜汪)

每条直线至少经过两个点,我们不妨在经过的所有点中的第二个点统计它

设f[i][j]表示i * j的答案,那么显然可以用f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + 以(i, j)这个点为第二个经过的点的直线

这样的直线的数量与(1, 1) ~ (i - 1, j - 1)中与(i, j)横纵坐标差与(i, j)互质的点的数量有关(还要再减掉一写)

而这个数量等于(1, 1) ~ (i - 1, j - 1)中与(0, 0)横纵坐标差与(i, j)互质的点的数量

具体的参照http://blog.csdn.net/accelerator_/article/details/26132853

预处理时间复杂度O(n2)后可以做到O(1)回答询问

 

rjl的算法:枚举有效包围盒的数量

这样每次都是O(n2)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<iostream>
 6 
 7 using namespace std;
 8 
 9 void setIO(const string& s) {
10     freopen((s + ".in").c_str(), "r", stdin);
11     freopen((s + ".out").c_str(), "w", stdout);
12 }
13 template<typename Q> Q read(Q& x) {
14     static char c, f;
15     for(f = 0; c = getchar(), !isdigit(c); ) if(c == '-') f = 1;
16     for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - '0';
17     if(f) x = -x;
18     return x;
19 }
20 template<typename Q> Q read() {
21     static Q x; read(x); return x;
22 }
23 
24 const int N = 300 + 10;
25 
26 int g[N][N];
27 
28 int main() {
29 #ifdef DEBUG
30     freopen("in.txt", "r", stdin);
31     freopen("out.txt", "w", stdout);
32 #endif
33     
34     for(int i = 1; i <= 300; i++) {
35         for(int j = i; j <= 300; j++) {
36             g[i][j] = g[j][i] = __gcd(i, j);
37         }
38     }
39     
40     int n, m;
41     while(scanf("%d%d", &n, &m), n) {
42         int ans = 0;
43         for(int a = 1; a <= m; a++) {
44             for(int b = 1; b <= n; b++) {
45                 if(g[a][b] == 1) {
46                     int c = max(0, m - (a << 1)) * max(0, n - (b << 1));
47                     ans += (m - a) * (n - b) - c;
48                 }
49             }
50         }
51         printf("%d
", ans << 1);
52     }
53     
54     return 0;
55 }
View Code
原文地址:https://www.cnblogs.com/showson/p/5106050.html