1393 - Highways
Hackerland is a happy democratic country with m×n cities, arranged in a rectangular m by n grid and connected by m roads in the east-west direction and n roads in the north-south direction. By public demand, this orthogonal road system is to be supplemented by a system of highways in sucha way that there will be a direct connection between any pair of cities. Each highway is a straight line going through two or more cities. If two cities lie on the same highway, then they are directly connected.If two cities are in the same row or column, then they are already connected by the existing orthogonal road system (each east-west road connects all the m cities in that row and each north-south road connects all the n cities in that column), thus no new highway is needed to connect them. Your task is to count the number of highway that has to be built (a highway that goes through several cities on a straight line is counted as a single highway).
Input
The input contains several blocks of test cases. Each test case consists of a single line containing two integers 1n , m300 , specifying the number of cities. The input is terminated by a test case with n = m = 0 .
Output
For each test case, output one line containing a single integer, the number of highways that must be built.
Sample Input
2 4 3 3 0 0
Sample Output
12 14
大意:
给出一个 n*m 的网格,求出至少经过两个点的直线的总数.
思路:
最开始的思想是先全部算,然后再去重... 这个方法能做,但是不是最好的方法.
先描述一下这个方法,枚举子矩形,然后计算出这样的直线能够放多少条, O(nm) 回答每个询问.
更好的方法是预处理的递推.
令 add[i][j] 为尺寸为 i,j 的长方形 (i, j) 顶点的贡献.
那么 add[i][j] = add[i-1][j] + add[i][j-1] (1) - add[i-1][j-1] (2) + (gcd(i,j) == 1) (3).
三个部分的含义分别是:
add[i-1][j], add[i][j-1] 把上下的小一点的矩形贡献的直线向下(右) 平移一个单位依然为新的贡献.
于是重复的部分就是 add[i-1][j-1] .
当 i,j 坐标互质的时候, 一条新的线段产生.
同理, 我们在计算 ans[i][j] 的时候, 要减掉 ans[i/2][j/2] 这是因为, ans[i/2][j/2] 的线段倍长之后全部都在 ans[i][j] 内.
所以这个就快一些.
1 #include<cstdlib> 2 #include<cstdio> 3 #include<iostream> 4 using namespace std; 5 const int maxn = 350; 6 long long f[maxn][maxn],ans[maxn][maxn]; 7 int n,m; 8 int gcd(int x,int y){ 9 return !y ? x : gcd(y,x%y); 10 } 11 void init(){ 12 for(int i = 1; i <= 310; ++i) 13 for(int j = 1; j <= 310; ++j) 14 f[i][j] = f[i][j-1] + f[i-1][j] - f[i-1][j-1] + (gcd(i,j) == 1); 15 for(int i = 1; i <= 310; ++i) 16 for(int j = 1; j <= 310; ++j) 17 ans[i][j] = ans[i-1][j] + ans[i][j-1] - ans[i-1][j-1] + f[i][j] - f[i/2][j/2]; 18 } 19 int main() 20 { 21 freopen("highway.in","r",stdin); 22 freopen("highway.out","w",stdout); 23 init(); 24 while(cin >> n >> m, n+m) 25 cout << ans[n-1][m-1] * 2 << endl; 26 return 0; 27 }