1.P2241统计方形:
对于这个题的思路我整理了下思路:
1.正方形个数+长方形个数=所有方形个数
2.对于一个n*m的棋盘我们可以考虑先找出来其中较小的一边,这样他就代表了能找出正方形边长的最大值,假设这时候n<=m,那么正方形的个数就等于边长为1的正方形个数加到边长为n的正方形个数,而以下是计算正方形个数的代码;
long long squares = 0;
for (int side = 1; side <= min(n, m); ++side) {
squares += (n - side + 1) * (m - side + 1);
其中n和m是我们输出的棋盘的两个边长
3.接下来我们考虑计算长方形的所有个数,但是我们要找的是不包括正方形的长方形个数,所以直接找长方形比较困难我们不妨使用所有方形个数减去正方形个数就可以得到长方形的个数,那么我们接下来考虑怎样计算所有方形个数:
我们不妨将棋盘看成一个二维的直角坐标系,那么这时候我们可以从0到n和0到m分别考虑选择2个点作为方形的四个顶点,这样计算得到的就是所有的方形个数最后减去上面的正方形个数就可以得到想要的长方形个数,所以方形的计算方法:C(n+1,2)×C(m+1,2)=2(n+1)⋅n×2(m+1)⋅m
所以长方形的计算代码如下:
long long rectangles = 1LL * n * (n + 1) / 2 * m * (m + 1) / 2 - squares;
最后就是这道题目的完整代码:
#include <iostream>
using namespace std;
int main() {
// 读取输入的 n 和 m
int n, m;
cin >> n >> m;
// 计算正方形数量
long long squares = 0;
for (int side = 1; side <= min(n, m); ++side) {
squares += (n - side + 1) * (m - side + 1);
}
// 计算长方形数量(不包含正方形)
long long rectangles = 1LL * n * (n + 1) / 2 * m * (m + 1) / 2 - squares;
// 输出结果
cout << squares << " " << rectangles << endl;
return 0;
}
2.P2089烤鸡:
这道题目我一开始看着觉得并不是很难可是在解答的过程中让我发现自己的想法还是太草率了,这道题目的难度就在于需要先输出方案数再枚举输出每一种方案,所以我们一开始需要先计算出所有的方案个数,同时利用枚举在每次计算中需要一个东西存储下每一种方案以便最后输出,所以这个题可以考虑使用动态数组来进行存储,以下是代码实现:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int target;
cin >> target;
if (target < 10 || target > 30) {
cout << 0 << endl;
return 0;
}
int count = 0;
// 存储每种方案的数组
vector<vector<int>> result;
// 枚举每种方案
for (int a = 1; a <= 3; ++a) {
for (int b = 1; b <= 3; ++b) {
for (int c = 1; c <= 3; ++c) {
for (int d = 1; d <= 3; ++d) {
for (int e = 1; e <= 3; ++e) {
for (int f = 1; f <= 3; ++f) {
for (int g = 1; g <= 3; ++g) {
for (int h = 1; h <= 3; ++h) {
for (int i = 1; i <= 3; ++i) {
for (int j = 1; j <= 3; ++j) {
int sum = a + b + c + d + e + f + g + h + i + j;
if (sum == target) {
++count;
result.push_back({a, b, c, d, e, f, g, h, i, j});
}
}
}
}
}
}
}
}
}
}
}
// 输出方案总数
cout << count << endl;
// 输出每种方案
if (count > 0) {
// 对结果按字典序排序
sort(result.begin(), result.end());
for (const auto& combination : result) {
for (int i = 0; i < 10; ++i) {
cout << combination[i] << " ";
}
cout << endl;
}
}
return 0;
}
首先由于十种配料并且每种配料都只能放一到三克,因此需要考虑当没有满足条件的方案时,输出0的情况,然后利用十个for循环进行暴力枚举,当有一种方案符合要求的时候让计数器加一,并存储在二维向量result之中(稍等会给出这个数据结构的解释),然后输出计数器的结果,当计数器大于0时,先对每种符合要求的方案按字典序排序以便符合题目要求进行输出,最后遍历每一种方案按字典序顺序进行输出。
下面给出关于vector数据结构的解释:
-
vector<int>
: 这是一个存储整数的动态数组(或向量),可以动态调整大小。 -
vector<vector<int>>
: 这是一个存储整数向量的动态数组,也就是二维向量。可以看作一个表格,其中每行都是一个向量,每个向量都是整数。
在这个特定的情境中,result
用于存储所有符合条件的方案。每一行代表一个方案,每一列代表一个配料的用量。让我们通过一个简单的例子来说明:
vector<vector<int>> result;
// 假设有两个符合条件的方案
result.push_back({1, 2, 3, 1, 2, 3, 1, 2, 3, 1});
result.push_back({3, 3, 2, 1, 1, 3, 2, 2, 1, 1});
在这个例子中,result
是一个包含两个向量的向量。每个向量都代表一个符合条件的方案。例如,第一个向量 {1, 2, 3, 1, 2, 3, 1, 2, 3, 1}
表示第一种方案,其中每个数字对应一种配料的用量。
在整个代码中,我们使用 result.push_back(...)
将符合条件的方案添加到 result
中。最后,我们按照题目要求对 result
进行排序,并遍历输出每个方案。
实际上这道题目应该还可以使用函数的递归进行解决不过我并没有进行深究,如果读者感兴趣可以自己实践一下同时欢迎对我进行指教。
来看一下第三道题。
3.三连击:
接下来让我们先一起见证一下一开始只有四十分的代码
抽象的辣眼睛。
下面是纠正之后的代码:
#include<iostream>
using namespace std;
int k1,k2,k3;
int t1,t2,t3;
int a[10];
int m=0,count=0;
int main(){
cin>>k1>>k2>>k3;
for(int i=1;i<=1000/k3;i++){
t1=i*k1;
t2=i*k2;
t3=i*k3;
if(t3>999) break;
for(int j=1;j<=3;++j){
a[t1%10]++;
a[t2%10]++;
a[t3%10]++;
t1/=10;
t2/=10;
t3/=10;
}
for(int j=1;j<=9;++j) if(a[j]!=1)
{
m=1;
break;
}
for(int j=1;j<=9;j++) a[j]=0;
if(m==0){
cout<<i*k1<<' '<<i*k2<<' '<<i*k3<<endl;
count++;
}
else m=0;
}
if(count==0) cout<<"No!!!";
return 0;
}
其中大概的思路就是我们从一枚举到1000/k3,对于每次循环我们都将枚举的数字分别乘上k1,k2,k3,当t3大于999时候,意味着不必再继续枚举了,因为继续枚举t3肯定也是大于999的,然后我们引入了一个数组记录一到九在每次循环中出现的次数,同时引入了一个变量m,当数组中的元素不为1时,将m记录为1代表等等不必进行输出这一对数字,同时对数组元素清0方便进行下一次循环,然后判断m是否为0,如果为0就代表这一组数字符合要求,按照题目要求输出就行,同时计数器加一,否贼将m重新记录为0进行下一次判断,最终循环结束后判断计数器是否为0,如果为0,就直接输出No!!!,注意题目是三个感叹号。