留坑(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 }