题目2 : 长方形

时间限制:2000ms
单点时限:1000ms
内存限制:256MB
描述
在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。

输入
输入文件包含多组测试数据。
第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。
每组数据为三个用空格隔开的整数 N,M,K。

1 ≤ T ≤ 100
0 ≤ K ≤ N * M
小数据:0 < N, M ≤ 30
大数据:0 < N, M ≤ 30000

输出
对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最多能找到的符合条件的长方形数量。所有数据按读入顺序从1开始编号。

样例输入
3
3 3 8
4 5 13
7 14 86
样例输出
Case #1: 5
Case #2: 18
Case #3: 1398

先看一道微软2013校园招聘笔试题:

How many rectangles you can find from 3*4 grid?
A. 18
B. 20
C. 40
D. 60
E. None of above is correct

从纵向和横向的各条边中,每各选出两条边就会有一个由四个交点组成的矩形,所以答案是C32×C42 = 60.

回归到本题,可以枚举纵向或横向的边数:2~N(或M),对于多余的石子,加入到行或列中(前提是行或列没有达到最大值)。

算法:

假如现在有m行n列,k=K-m×n,此时可得到的最大矩形数目是:Cm2×Cn2 + Ck2 × max(m, n), m <M && n < N.

枚举m或n即可。

优化:

事实上,不需要枚举这么多次,假设N < M,只要枚举2~min(N, K½)即可.

#include<cstdio>
#include<cmath>
using namespace std;
void swap(int& a, int& b) {
    int t = a;
    a = b;
    b = t;
}
int main() {
    int T, N, M, K;
    scanf("%d", &T);
    int m, n, tmp, ans;
    for(int i = 1; i <= T; ++i) {
        ans = 0;
        scanf("%d%d%d", &N, &M, &K);
        if(N > M)//使M最大
            swap(N, M);
        tmp = sqrt(K);
        n = N > tmp ? tmp : N;
        m = M;
        while(n * m > K)
            --m;
        while(n >= 2 && m <= M) {
            tmp = (n * m * (n - 1) * (m - 1)) >> 2;
            int k = K - m * n;
            if(m < M)
                tmp += (k * (k - 1) * m) >> 1;
            else
                tmp += (k * (k - 1) * n) >> 1;
            ans = tmp > ans ? tmp : ans;
            --n;
            m = K / n;
        }
        printf("Case #%d: %d\n", i, ans);
    }
    return 0;
}

 

 

 

posted @ 2014-04-08 10:50  Shanks-香克斯  阅读(210)  评论(0编辑  收藏  举报