有一个 n✖m方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。
矩形包含长方形和正方形,因此可以算出棋盘有多少个矩形,再找出有多少个正方形,两个相减就可以算出长方形的个数。这里枚举的方法比较多,可以枚举点,也可以枚举边。
我做的时候是枚举边。横向所有可能的边长为((n + 1) * n) / 2,纵向所有可能的边长为((m + 1) * m) / 2,则棋盘包含的所有的矩形个数为两式相乘。再计算正方形的个数,正方形最大边长一定是m和n中的较小的那一个,于是再循环枚举所有可能的正方形边长,即1、2、3、…、min(m,n),再相减就能得到长方形的个数。
#include
#include
using namespace std;
int main()
{
long long n, m;
long long seq = 0; //正方形个数
long long rec, sum; //长方形个数、矩形总个数
scanf("%lld", &n);
scanf("%lld", &m);
long long x = n;
long long y = m;
sum = (((n + 1) * n) / 2) * (((m + 1) * m) / 2);
for(int i = 1; i <= min(m, n); i++)
{
seq += x * y;
x--;
y--;
}
rec = sum - seq;
printf("%lld %lld", seq, rec);
return 0;
}
某国法律规定,只要一个由 N✖M 个小方块组成的旗帜符合如下规则,就是合法的国旗。
现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。
小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。
首先,三种颜色都要占一行,然后从边界开始枚举每一种情况所需要操作的次数,记录最小值
#include
#include
#include
#define N 55
using namespace std;
char flag[N][N];
int min_num = 10000;
int main()
{
int n, m;
int step;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
cin >> flag[i][j];
}
for(int i = 1; i <= n - 2; i++) //白与蓝的边界
{
for(int j = i + 1; j <= n - 1; j++) //蓝与红的边界
{
step = 0;
//开始枚举
for(int k = 1; k <= i; k++)
for(int l = 1; l <= m; l++)
{
if(flag[k][l] != 'W')
step++;
}
for(int k = i + 1; k <= j; k++)
for(int l = 1; l <= m; l++)
{
if(flag[k][l] != 'B')
step++;
}
for(int k = j + 1; k <= n; k++)
for(int l = 1; l <= m; l++)
{
if(flag[k][l] != 'R')
step++;
}
min_num = min(min_num, step);
}
}
cout << min_num;
return 0;
}
呐呐呐,这道题太过于二次元我就不写了吧(逃
这题思路其实比较容易想到。遍历一个二维数组,然后遇到 “.” 的就看右方和下方(也可以左方和上方)相距K格内是否有障碍物(即 “#” ),如果没有,则站位方式++,枚举结束输出。
此外需要注意的是,当队伍只有一个人(即K=1)的时候,由于右方和下方是相同的情况,所以等于同一个点枚举了两次,此时最终结果要除以2
#include
#define N 105
using namespace std;
char a[N][N];
int main()
{
int r, c, k;
int sum = 0;
cin >> r >> c >> k;
for(int i = 1; i <= r; i++)
for(int j = 1; j <= c; j++)
cin >> a[i][j];
for(int i = 1; i <= r; i++)
{
for(int j = 1; j <= c; j++)
{
if(a[i][j] == '.')
{ int tmp_1 = 0;
int tmp_2 = 0;
//枚举点的右边
for(int m = 1; m < k; m++)
{
if(a[i][j + m] != '.')
{
tmp_1 = 1;
break;
}
if(j + m > c) //越界处理
{
tmp_1 = 1;
break;
}
}
if(tmp_1 == 0)
sum++;
//枚举点的下边
for(int m = 1; m < k; m++)
{
if(a[i + m][j] != '.')
{
tmp_2 = 1;
break;
}
if(i + m > r) //越界处理
{
tmp_2 = 1;
break;
}
}
if(tmp_2 == 0)
sum++;
}
}
}
//特判
if(k == 1)
sum /= 2;
cout << sum;
return 0;
}
为 151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 是回文质数。
写一个程序来找出范围 [a,b] (5 <= a < b <= 100,000,000)间的所有回文质数。
虽然此题是枚举所有的数,但个人认为严格意义上这并不算一道枚举题,因为问题核心就是回文数判断和质数判断两部分,所以整个程序就分为三块:判断回文数、判断质数、枚举。
1、回文数的判断:将数字反过来,如果相等则为回文数
int Judge_Palindromes(long long x)
{
long long y = x, num = 0;
while(y != 0)
{
num = num * 10 + y % 10;//上一次数字的记录进位再加上下一位数
y /= 10;
}
if(num == x)
return 1;
else
return 0;
}
2、质数判断:开根号以减少运算时间
int Judge_Prime(long long x)
{
long long tmp = sqrt(x); //减小计算量
for(int i = 2; i <= tmp; i++)
{
if(x % i == 0) //如果有一个可以整除,则不是质数
return 0;
}
return 1;
}
因为最后TLE而增加特例来过题目的我是屑(逃
#include
#include
using namespace std;
long long a, b;
//回文数判断
int Judge_Palindromes(long long x)
{
long long y = x, num = 0;
while(y != 0)
{
num = num * 10 + y % 10;//上一次数字的记录进位再加上下一位数
y /= 10;
}
if(num == x)
return 1;
else
return 0;
}
//质数判断
int Judge_Prime(long long x)
{
long long tmp = sqrt(x); //减小计算量
for(int i = 2; i <= tmp; i++)
{
if(x % i == 0) //如果有一个可以整除,则不是质数
return 0;
}
return 1;
}
int main()
{
cin >> a >> b;
for(long long i = a; i <= b; i++)
{
if(i==9989900) //如果到了这个数,就break
break;
if(Judge_Palindromes(i) == 1)
{
if(Judge_Prime(i) == 1)
cout << i << endl;
}
}
return 0;
}