First, the first question, there are n*m points, in these points, how many lines, after at least two points, and not horizontal or vertical.

Analysis: Because of symmetry, we only ask for a line in one direction. The problem is divided into two processes, the first process is to find out the n*m rectangle, Dp[i][j] represents the end in this rectangle is to (i,j) this point to meet test instructions straight line number, then, With DP, you can draw a recursive relationship: the number of lines that meet the test instructions in the left and right two rectangles of the length and width of 1, minus the lines in the rectangle that they have in common (the tolerance minus the repeating part), and then whether the point from the top-left corner (i,j) can form a line, the condition is GCD (i,j) is equal to 1.

Then the second process is to recursive the answer, set ans[i][j] in this rectangle to meet the number of test instructions, then the same, can be recursive by the above tolerance, at the same time, but also add the rectangle to (i,j) this point satisfies the number of bars, in addition to subtract half the size of the line to this point of the number of lines, Because if (i,j) is (6,8), then half-scale, (3,4) to this point of the line and to (6,8) this line is duplicated.

This completes the topic (don't forget to multiply by 2 at the end). See the code for details:

1#include <stdio.h>2#include <algorithm>3#include <string.h>4#include <iostream>5#include <vector>6#include <queue>7 using namespacestd;8typedefLong Longll;9 Const intN = -+5;Ten One intDp[n][n]; A intAns[n][n]; - - intgcdintAintb) {returnA%B?GCD (b,a%b): b;} the - voidInit () - { - for(intI=1; i<n;i++) + { - for(intj=1; j<n;j++) + { ADP[I][J] = dp[i-1][J] + dp[i][j-1]-dp[i-1][j-1] + (GCD (i,j) = =1); at } - } - for(intI=1; i<n;i++) - { - for(intj=1; j<n;j++) - { inANS[I][J] = ans[i-1][J] + ans[i][j-1]-ans[i-1][j-1] + dp[i][j]-dp[i>>1][j>>1]; - } to } + } - the intMain () * { $ init ();Panax Notoginseng intn,m; - while(SCANF ("%d%d", &n,&m) = =2) the { + if(n==0&& m==0) Break; Aprintf"%d\n",2*ans[n-1][m-1]); the } +}

The second question is similar to the question. The possibility of selecting 3 points at all points is then subtracted from a horizontal or vertical line, minus the repetition of the same slash. Quite similar, see the code in detail:

1#include <stdio.h>2#include <algorithm>3#include <string.h>4#include <iostream>5#include <vector>6#include <queue>7 using namespacestd;8typedefLong Longll;9 Const intN = ++5;Ten One ll Dp[n][n]; A ll Ans[n][n]; - - intgcdintAintb) {returnA%B?GCD (b,a%b): b;} the - voidInit () - { - for(intI=1; i<n;i++) + { - for(intj=1; j<n;j++) + { ADP[I][J] = dp[i-1][J] + dp[i][j-1]-dp[i-1][j-1] + (LL) (GCD (I,J)-1); at } - } - for(intI=1; i<n;i++) - { - for(intj=1; j<n;j++) - { inANS[I][J] = ans[i-1][J] + ans[i][j-1]-ans[i-1][j-1] +Dp[i][j]; - } to } + } - thell C (ll x) {returnx* (x1) * (X-2)/6;} * $ intMain ()Panax Notoginseng { - init (); the intn,m; + intCNT =1; A while(SCANF ("%d%d", &n,&m) = =2) the { + if(n==0&& m==0) Break; -ll Ans = C ((n+1) * (m+1))-(n+1) *c (m+1)-(m+1) *c (n+1); $Ans-=2*Ans[n][m]; $cout<<" Case"<<cnt++<<": "<<Ans<<Endl; - } -}

However, both of the points to note is that the recursive DP when the three rectangles are in the lower right corner (because the number of bars is unchanged because of the downward or right translation of a unit), so that if the recursion is to consider from this point to (I,J) this point of the situation can be, while the recursive ans, The rectangle is the upper left side, then, as long as the entire large rectangle inside to (i,j) this point of the situation can be. Of course, purely personal understanding.

UVA 1393 Highways,uva 12075 counting triangles--(combination number, DP)