UVALive 3295

题目大意:见刘汝佳《算法竞赛入门经典——训练指南》P173

解题思路:

  每一个合法的三角形的三个顶点都不在同一直线上,那么问题其实就是在求所有不全在同一直线上的三点的组合数。

  我们可以利用容斥原理,先求出所有的三个顶点的组合数C[(n+1)*(m+1)][3]。全在同一直线上的三个网格顶点有三种:三点在同一水平线上的,三点在同一竖直线上的,三点在同一斜线上的。前两种不难求,因此不再赘述,这里重点讲解第三种。

  设三点坐标为(x1,y1),(x2,y2),(x3,y3),且x1 < x2 < x3,y1 < y2 < y3,设 x2-x1 = i,x3-x2 = j,当且仅当 i*(y3-y2) = j*(y2-y1)时,三点在同一斜线上。那么我们可以枚举 i 和 j ,求出 g = gcd(i,j),对于每一个(i,j),再从 1 开始枚举 k ,则此时 y3-y2 = k*j/g,y2-y1 = k*i/g(当 y3 - y1 >= m+1时退出循环),这样就可以知道 x3-x1 和 y3-y1 的值了,接下来就只需要求出放得下多少条这样的斜线就可以。

AC代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn=1002001+3;
 8 ll C[maxn][5];
 9 void init(){
10     C[0][0]=1;
11     C[1][1]=C[1][0]=1;
12     for(int n=2;n<maxn;n++){
13         C[n][0]=1;
14         if(n<=3)    C[n][n]=1;
15         for(int m=1;m<min(4,n);m++){
16             C[n][m]=C[n-1][m-1]+C[n-1][m];
17         }
18     }
19 }
20 int gcd(int a,int b){
21     if(b==0)    return a;
22     return gcd(b,a%b);
23 }
24 int main(){
25     init();
26     int n,m;
27     int kase=1;
28     while(scanf("%d%d",&n,&m)==2&&n&&m){
29         n++,m++;
30         if(n>m) swap(n,m);
31         ll ans=C[n*m][3];
32         ans-=C[n][3]*m;
33         ans-=C[m][3]*n;
34         ll t=0;
35         for(int i=1;i<n;i++){
36             for(int j=1;i+j<n;j++){
37                 int gd=gcd(i,j);
38                 for(int k=1;;k++){
39                     int id=k*j/gd,ij=k*i/gd;
40                     if(id+ij>=m)  break;
41                     t+=(n-(i+j))*(m-(k*(i+j)/gd));
42                 }
43             }
44         }
45         ans-=t*2;
46         printf("Case %d: %lld\n",kase++,ans);
47     }
48     return 0;
49 }

 

posted @ 2017-10-10 18:45  Blogggggg  阅读(125)  评论(0编辑  收藏  举报