HDU 5100 Chessboard (用k×1的矩形覆盖n×n的正方形)(找规律)

本文探讨了如何用k×1的矩形覆盖n×n的正方形棋盘,证明了无论n和k的值如何,未覆盖到的方格数m(n, k)总是一个完全平方数。通过分析不同情况,展示了当n≥k时如何达到最优覆盖方案,并给出具体案例和代码实现。" 86500059,8246684,使用悲观锁与乐观锁解决并发超发现象,"['并发控制', '数据库', 'Java开发', '锁机制', '分布式系统']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Chessboard

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 799    Accepted Submission(s): 335


Problem Description
Consider the problem of tiling an n×n chessboard by polyomino pieces that are k×1 in size; Every one of the k pieces of each polyomino tile must align exactly with one of the chessboard squares. Your task is to figure out the maximum number of chessboard squares tiled.
 

Input
There are multiple test cases in the input file.
First line contain the number of cases T ( T10000 ). 
In the next T lines contain T cases , Each case has two integers n and k. ( 1n,k100 )
 

Output
Print the maximum number of chessboard squares tiled.
 

Sample Input
  
2 6 3 5 3
 

Sample Output
  
36 24
 

Source
 

题目大意:在一个n × n的棋盘上,铺k × 1的矩形,问棋盘被覆盖的最大面积。

解题思路:

用 k × 1 的小矩形覆盖一个 n × n 的正方形棋盘,如果n不是k的倍数,往往是不能实现完全覆盖的。但是,在众多覆盖方案中,一定会有一种覆盖方案会让没有覆盖到的方格个数达到最少。我们不妨就用 m(n, k) 来表示这个数目。而对这个数 m(n, k) ,我们有一个结论:无论n和k是多少, m(n, k) 一定是一个完全平方数。

证明:无论n和k是多少, m(n, k) 一定是一个完全平方数。


如果 n < k ,显然棋盘里一个k × 1矩形也放不下,因而此m(n, k) =n × n,这是一个完全平方数。下面我们只考虑 n ≥ k 就可以了。


我们先来证明这样一个事实:如果某个覆盖方案当中,仅剩下一个 s × s 的小正方形区域没有覆盖到,其中 s ≤ k / 2 ,那么这样的方案一定是最优的。首先,在棋盘中的每个格子里都填上一个数,使得从最左下角出发,各个对角线上的数依次为 0, 1, 2, …, k – 1, 0, 1, 2, …, k – 1, … (如上图所示:n = 9, k = 6 )。那么,把一个 k × 1 的小矩形放在棋盘中的任意位置,它总会覆盖每种数字各一个。假设某个覆盖方案当中,仅剩下一个 s × s 的小正方形区域没有覆盖到。注意到,任意一个 s × s 的小正方形区域里最多只会出现 2s – 1 种不同的数,因此如果 s ≤ k / 2 ,那么这个 s × s 的小正方形区域里一定会缺失至少一种数,比方说 x (在上图中,右上角的那个 3 × 3 的空白区域里就缺数字 5 ,因而我们可以取 x = 5 )。由此可以推出,此时小矩形的数目已经达到了最大值,任何其他覆盖方案都不可能包含更多的小矩形,因为每个小矩形都必然会覆盖到一个 x ,然而在刚才的覆盖方案中,所有的 x 都已经被覆盖到了。



有趣的是,当 n ≥ k 时,让整个棋盘仅剩一个边长不超过 k / 2 的小正方形区域没有覆盖到,这是一定能做到的。不妨把 n 除以 k 的余数记作 r 。如果 r ≤ k / 2 ,那么我们可以直接用横着的小矩形从左向右填充棋盘,再用竖着的小矩形填充余下的部分,最终会剩下 r × r 的小正方形区域。上图所示的就是 n = 22 并且 k = 5 的情况,注意到 22 除以 5 的余数为 2 ,确实小于等于除数 5 的一半。可见,对于这类情况,我们都有 m(n, k) = r × r,这是一个完全平方数。



如果 r > k / 2 呢?我们可以用和刚才类似的方法填充棋盘,使得棋盘右上角仅剩一个 (r + k) × (r + k) 的正方形区域。然后再用 4r 个小矩形像风车一样填充这个 (r + k) × (r + k) 的区域,使得正中间只剩下一个边长为 k – r 的小正方形区域。由于 k – r < k / 2 ,因而此时的覆盖方案再次达到最优。上图所示的就是 n = 22 并且 k = 6 的情况,注意到 22 除以 6 的余数为 4 ,确实大于除数 6 的一半。可见,对于这类情况,我们有 m(n, k) = (k – r)2 ,这仍然是一个完全平方数。


代码如下:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define sqr(x) (x) * (x)
#define mod 1000000007
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
int main()
{
    int i,j,k,n,t;
    while(~scanf("%d",&t))
    {
        while(t--)
        {
            scanf("%d%d",&n,&k);
            if(k>n)
                printf("0\n");
            else
            {
                int r=n%k;
                if(r<=k/2)
                {
                    printf("%d\n",n*n-r*r);
                }
                else
                {
                    printf("%d\n",n*n-(k-r)*(k-r));
                }
            }
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值