【题解】P1548 [NOIP 1997 普及组] 棋盘问题
题目背景
NOIP1997 普及组第一题
题目描述
设有一个 N×MN \times MN×M 方格的棋盘 (1≤N≤100,1≤M≤100)(1≤N≤100,1≤M≤100)(1≤N≤100,1≤M≤100)
求出该棋盘中包含有多少个正方形、多少个长方形(不包括正方形)。
例如:当 N=2,M=3N=2, M=3N=2,M=3 时:
正方形的个数有 888 个:即边长为 111 的正方形有 666 个;边长为 222 的正方形有 222 个。
长方形的个数有 101010 个:
即
- 2×12 \times 12×1 的长方形有 444 个:
- 1×21 \times 21×2 的长方形有 333 个:
- 3×13 \times 13×1 的长方形有 222 个:
- 3×23 \times 23×2 的长方形有 111 个:
输入格式
一行两个整数 N,MN,MN,M。
输出格式
一行两个整数,表示正方形的个数与长方形的个数。
输入输出样例 #1
输入 #1
2 3
输出 #1
8 10
题目分析
题目需要我们统计n×mn\times mn×m 方格的棋盘中正方形、长方形(不包括正方形)的个数。
可以考虑枚举所有可能的长、宽,相等为正方形,剩余的就是长方形。整体时间复杂度为O(nm)O(nm)O(nm)。
也可以考虑优化一下,枚举所有可能的正方形边长,根据边长计算对应的正方形个数。对于长方形个数,则可以通过总数减去正方形个数进行获取。
对于边长为x(1≤x≤min(n,m))x(1\le x \le \min(n,m))x(1≤x≤min(n,m))的正方形,个数为 (n−x+1)×(m−x+1)(n-x+1)\times (m-x+1)(n−x+1)×(m−x+1)。
对于矩形可以视为由水平、垂直两个方向各选两条线构成的图形。n×mn\times mn×m 方格的棋盘,长宽各有 n+1n+1n+1和m+1m+1m+1条线,故矩形总数为 Cn+12×Cm+12C_{n+1}^2 \times C_{m+1}^2Cn+12×Cm+12 即(n+1)×n2×(m+1)×m2\frac{(n+1)\times n}{2}\times \frac{(m+1)\times m}{2}2(n+1)×n×2(m+1)×m 。
利用数学性质,整体复杂度可以降为 O(n)O(n)O(n)。
代码实现
复杂度O(nm)写法
#include<iostream>
using namespace std;
int m,n,cnt1,cnt2;
int main(){cin>>m>>n; for(int i=0;i<=m;i++){for(int j=0;j<=n;j++){for(int k=i+1;k<=m;k++){for(int l=j+1;l<=n;l++){if(k-i==l-j){//如果长和宽相等,及正方形 cnt1++; }else{//不相等就是长方形 cnt2++; } } }}} cout<<cnt1<<" "<<cnt2; return 0;
}
复杂度O(n)写法
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 1e5 + 5;
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int n,m;int sum1=0,sum2=0;cin>>n>>m;for(int i=1;i<=min(n,m);i++){sum1+=(n-i+1)*(m-i+1);}sum2=(n*(n+1)/2)*(m*(m+1)/2)-sum1;cout<<sum1<<" "<<sum2;return 0;
}