UVALive 3720 UVA 1393 Highways

这是白书二代上的一个组合计数里面的一道练习题。

我用的方法是枚举在x*y的方格中放置一条对角线,也可以理解为枚举斜率。

如图,先来看这样一个问题,n=m=4,即此时有3行3列的方格的时候,可以放置斜率k=-1的直线有多少条。

首先我们把每个格子都标上号。如图,我最多只能放置5条k=-1的直线。

当我枚举在1*1的方格中放置对角线的时候(当然此时斜率k=-1),一共可以放置9条对角线。

然而事实上斜率k=-1的对角线只需要5条就可以了,多出来了4条。那么是哪里多出来了这4条呢?

我们注意看所有2*2的方格,他们多有的右下角的那条都是多余的。如图:

很显然,我们需要删掉1245中的5,2356中的6,4578中的8,5689中的9,此时留下来的123475条直线可以代表所有斜率为-1的直线。

同理,当n!=m的时候,结果也是一样的。

再来考虑斜率不是-1的情况(当然我这里只是举了斜率为负的例子,斜率为正的情况和斜率为负的情况必定都是一样的,最后在结果*2就可以了。)

其实道理还是一样的,如果gcd(x,y)=1,可以保证这样的斜率是第一次出现,则我们只需要把每x*y格看成是1格就行了。

如果gcd(x,y)=2,这样的斜率是第二次出现了,这就类似于上面所说的2*2的情况了,对于所有这样的矩形,他的右下角部分都是多余的。

贴一下我的代码:

View Code
 1 #include<cstdio>
 2 int gcd[310][310];
 3 int Gcd(int a,int b)
 4 {
 5     return b == 0 ? a : Gcd(b,a%b);
 6 }
 7 int main()
 8 {
 9     for(int i = 1;i <= 300;i++)
10         for(int j = i;j <= 300;j++)
11             gcd[i][j] = Gcd(i,j);
12     int n,m;
13     long long int ans;
14     while(scanf("%d%d",&n,&m) == 2)
15     {
16         if(!n && !m)    break;
17         n--;m--;
18         if(n > m)   n ^= m,m ^= n,n ^= m;
19         ans = 0;
20         for(int x = 1;x <= n;x++)
21         {
22             for(int y = x;y <= m;y++)   if(gcd[x][y] <= 2)
23             {
24                 if(x == y)
25                 {
26                     int tmp = (n-x+1)*(m-y+1);
27                     if(gcd[x][y] == 1)  ans += tmp;
28                     else                ans -= tmp;
29                 }
30                 else
31                 {
32                     int tmp = (n-x+1)*(m-y+1);
33                     if(x <= m && y <= n)    tmp += (m-x+1)*(n-y+1);
34                     if(gcd[x][y] == 1)      ans += tmp;
35                     else                    ans -= tmp;
36                 }
37             }
38         }
39         ans *= 2;
40         printf("%lld\n",ans);
41     }
42 }

 

posted @ 2013-05-07 15:43  浙西贫农  阅读(777)  评论(0编辑  收藏  举报