湖南省第八届程序设计竞赛G

题目G. 网格中的三角形

 

有一个nm列单位正方形组成的网格。不难发现一共有n+1条横线,m+1条竖线和它们形成的(n+1)(m+1)个交叉点。你可以选择三个不共线的交叉点,形成一个三角形。比如当n=m=1时,一共有4个交叉点,可以形成4个三角形。

 

问:有多少个三角形的面积在A和B之间(包含A和B)。

 

输入格式

输入第一行为数据组数T (T<=25)。每组数据为四个整数n, m, A, B (1<=n, m<=200, 0<=A<B<=nm)。

 

输出格式

对于每组数据,输出面积在A和B之间的三角形个数。

 

样例输入                                    样例输出

4

1 1 0 1

1 2 1 2

10 10 20 30

12 34 56 78

4

6

27492

1737488

代码

// Rujia Liu
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    int n, m, A, B;
    scanf("%d%d%d%d", &n, &m, &A, &B);
    if(n > m) swap(n, m);
    long long c = 0;
    for(int xx = 1; xx <= n; xx++)
    for(int yy = xx; yy <= m; yy++) {
      long long cc = 0;
      // one corner, no side or diagonal
      for(int x = 1; x < xx; x++) {
        // area2 = xx*yy*2 - (xx-x)*yy - xx*(yy-y) - x*y = (xx-x)*y + (xx*yy*2-(xx-x)*yy-xx*yy)
        int a = xx-x, b = xx*yy*2-(xx-x)*yy-xx*yy; // area2 = ay + b
        int y1 = 1, y2 = yy-1;
        y1 = max(y1, (max(1,A*2)-b-1)/a+1); // ay + b >= max(1,A*2)
        y2 = min(y2, (B*2-b)/a);            // ay + b <= B*2
        if(y1 <= y2) cc += 4 * (y2-y1+1);
      }
      // one diagonal, possibly one side
      for(int x = 0; x <= xx; x++) {
        // area2 = xx*y - x*yy
        int a = xx, b = -x*yy; // area2 = ay + b
        int y1 = 0, y2 = yy;
        y1 = max(y1, (max(1,A*2)-b-1)/a+1); // ay + b >= max(1,A*2)
        y2 = min(y2, (B*2-b)/a);            // ay + b <= B*2
        if(y1 <= y2) cc += 4 * (y2-y1+1);
      }
      // one side, not diagonal
      if(xx*yy >= A*2 && xx*yy <= B*2) cc += (xx + yy - 2) * 2;

      c += (long long)(n - xx + 1) * (long long)(m - yy + 1) * cc;
      if(xx != yy && xx <= m && yy <= n) c += (long long)(n - yy + 1) * (long long)(m - xx + 1) * cc;
    }
    cout << c << endl;
  }
  return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值