问题一:
P2241 统计方形(数据加强版)
题目描述
有一个 n×m 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。
输入格式
一行,两个正整数 n≤5000,m≤5000)。
输出格式
一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。
输入输出样例
输入
2 3
输出
8 10
问题分析:
- 智商不配做暴力枚举了,不知道为什么暴力枚举的题就算简单我也不会,这题本质找规律,这种题目我都不擅长…
- 但要注意的点是,题目虽然是int类型的m、n,但多次相乘要让m、n超出int界限,所以要开long long
正确代码:
#include <bits/stdc++.h>
using namespace std;
long long squ;
long long rec;
int main()
{
long long m,n;
cin>>n>>m;
//分别统计边长从1~min(m,n)的正方形
for(long long i=1;i<=m;i++)
{
for(long long j=1;j<=n;j++)
{
if(i==j)
{
squ+=(m-(i-1))*(n-(i-1));
}
else{
rec+=(m-(i-1))*(n-(j-1));
}
}
}
cout<<squ<<" "<<rec;
}
问题2:
P2089 烤鸡
走这
问题分析:
- 所有人除了我都会做的烤鸡
- 该题目声明10个变量for循环即可
正确代码:
#include <bits/stdc++.h>
using namespace std;
/*只用一个变量表示十种调料的状态是不可能的,因此,每个调料都要用变量表示*/
int a,b,c,d,e,f,g,h,i,j,k;//k用来记录方案个数
/*可以用一个数组,每个数组元素存储一个调料的状态*/
/*也可以在循环一次,二次循环分别输出方案数和调料各为多少*/
/*主要就在10个变量的创建每个从1~3变化,所以用一个变量代表调料,一个代表调料种类是不现实的*/
int tiao[1000000];
int m;//记录数组下标
int main()//因为输入的n是正整数,所以不用从0开始
{
int n;
cin>>n;
for(a=1;a<=3;a++)//表示调料a从1~3
{
for(b=1;b<=3;b++)
{
for(c=1;c<=3;c++)
{
for(d=1;d<=3;d++)
{
for(e=1;e<=3;e++)
{
for(f=1;f<=3;f++)
{
for(g=1;g<=3;g++)
{
for(h=1;h<=3;h++)
{
for(i=1;i<=3;i++)
{
for(j=1;j<=3;j++)
{
if(a+b+c+d+e+f+g+h+i+j==n)
{
k++;
}
}
}
}
}
}
}
}
}
}
}
cout<<k<<endl;
for(a=1;a<=3;a++)//表示调料a从1~3
{
for(b=1;b<=3;b++)
{
for(c=1;c<=3;c++)
{
for(d=1;d<=3;d++)
{
for(e=1;e<=3;e++)
{
for(f=1;f<=3;f++)
{
for(g=1;g<=3;g++)
{
for(h=1;h<=3;h++)
{
for(i=1;i<=3;i++)
{
for(j=1;j<=3;j++)
{
if(a+b+c+d+e+f+g+h+i+j==n)
{
cout<<a<<" ";
cout<<b<<" ";
cout<<c<<" ";
cout<<d<<" ";
cout<<e<<" ";
cout<<f<<" ";
cout<<g<<" ";
cout<<h<<" ";
cout<<i<<" ";
cout<<j<<endl;
}
}
}
}
}
}
}
}
}
}
}
}
问题三:
P1618 三连击(升级版)
走这
问题分析:
- 这题我的想法是用9个数字排列组合,有这种想法但是不会做…
- 看了题解,发现直接列举三位数即可
- 再利用条件可以减少枚举的量
正确代码:
#include <bits/stdc++.h>
using namespace std;
int nums[10];
/*可以直接列举三位数,这样就不用考虑不同的组合*/
bool Divide(int i)
{
nums[i%10]++;
if(nums[i%10]>1)
{
return false;
}
nums[i/10%10]++;
if(nums[i/10%10]>1)
{
return false;
}
nums[i/100]++;
if(nums[i/100]>1||(i/100)>=10)
{
return false;
}
return true;
}
int main()
{
int flag = 0;
int A,B,C;
cin>>A>>B>>C;
// int j,k;
// stringstream ss;
for(int i=123;i<=987;i++)
{
nums[0] = 2;
//通过判断条件直接求出另外两个三位数
if(Divide(i)&&Divide(i/A*B)&&(i%A==0)&&Divide(i/A*C))
{
cout<<i<<" "<<i/A*B<<" "<<i/A*C<<endl;
flag = 1;
}
else{
memset(nums,0,sizeof(nums));
}
}
if(flag==0)
{
cout<<"No!!!";
}
}
问题四:
P3392 涂国旗
走这
问题分析:
- 又是除了我所有人都会的涂国旗,一开始看错题目,以为可以间隔涂色= =
- 这里直接枚举每个颜色所占的行数即可
正确代码:
#include <bits/stdc++.h>
using namespace std;
int w[51];//这样就不用分别统计每行要涂的个数并且比较
int b[51];
int r[51];
int n,m;
/*分别表示把前i行涂成w\b\r三种颜色需要花费的格子数*/
/*
1~i行是白色 i+1~j是蓝色 j+1~N是红色
所以需要花费的格子数是 w(i)+b(j)-b(i)+r(N)-r(j)
*/
string s;
int check(char c)
{
int res=0;
for(int i=0;i<m;i++)
{
if(s[i]!=c)
{
res++;
}
}
return res;
}
int main()
{
cin>>n>>m;
// int res;
int less = 100000;
for(int i=1;i<=n;i++)
{
cin>>s;
w[i]=check('W')+w[i-1];//因为是表示前i行所以要加前面的
b[i]=check('B')+b[i-1];
r[i]=check('R')+r[i-1];
} //w(i)+b(j)-b(i)+r(N)-r(j) i必须>=1,j<N且j必须比i大
//此处需要枚举所有i、j的可能性
for(int i=1;i<n-1;i++)//i 从1开始表示只涂一行
{
for(int j=i+1;j<n;j++)
{
less = min(w[i]+b[j]-b[i]+r[n]-r[j],less);
}
}
cout<<less;
}
这里大佬的代码进行了预处理,我属实想不到
先统计每行涂成其他颜色需要花费的格子数,在枚举比较
问题五:
P1149 火柴棒等式
走这
问题分析:
- 压根不会,看了大佬的代码才懂,这里可以直接枚举和深度搜索两种方式
- 直接枚举将24根火柴最多能表示的数字作为界限,求出1到界限所有数分别用的火柴数,在循环枚举加数即可
暴力枚举的代码:
#include <cstdio>
using namespace std;
/*最多24根火柴棒,考虑一下极限,如果只有一个加数,那么这个加数最小是?
枚举0~这个最小数要用的火柴棒,将它们记录在一个数组里
然后再通过枚举0~最小数(加数、被加数、和)的火柴棒之和,看是否会是n
*/
int c[10] = {6,2,5,5,4,5,6,3,7,6};//通过基础的0~9可以求出其他的十位、百位等数
int a[3200] = {6};//用此数组,记录0~最小数所有数要用的火柴数
int j;
int cnt;
int n;
int main()//先给0位赋值,那么就不需要在循环里判断是否为0
{
scanf("%d",&n);
/*先求出1~最小数的火柴棒*/
for(int i=1;i<=2000;i++)//
{
/*如果是大数,需要将每一位分解,再用每一位的火柴数相加*/
j = i;
while(j>=1)//所以除了j自己等于0的情况,不可能有==0的情况
{
a[i] = c[j%10]+ a[i];//加完后,a[i]里面的值就是前位火柴数的总和
// k = j%10; 只有j%10才能得到位数上的0
j = j/10;//不用担心位数上有0的问题,j/10==0不可能是位数上的0,位数上的0前面必然还有数字
}//如果要得到j的每一位,那么就要让循环终止条件为j=0
}
for(int i=0;i<=1000;i++)
{
//再用一个循环表示另一个加数
for(int j=0;j<=1000;j++)
{
if(a[i]+a[j]+a[i+j]+4==n)//如果i=1000=j,i+j不弄2000就没有值
{
cnt++;
}
}
}
printf("%d",cnt);
return 0;
}
做题时一直想非个位数将其分解后每一位如何储存,没想到直接用赋值前的a数组存储,我的智商不配刷洛谷
也可以用dfs求解每个加数,将符合条件的加上:
正确代码:
#include <bits/stdc++.h>
using namespace std;
int n;
int a[2025]= {6, 2, 5, 5, 4, 5, 6, 3, 7,6};
int b[4];//存储等式的数字
int cnt;
void dfs(int s)//用来记录收到了第几个加数
{
for(int i=0;i<=1000;i++)//用一个循环即可寻找加数
{
if(n-a[i]>=0)
{
b[s] = i;
n-=a[i];
if(s==3)//先搜索3个数
{
if(b[1]+b[2]==b[3]&&n==0)
{
cnt++;
}
}else{
dfs(s+1);
//搜寻完后回溯
}
n+=a[i];
}
}
}
int main()
{
cin>>n;
n-=4;
/*因为要搜索哪些符合条件,所以要先将火柴棒数组赋值*/
for(int i=10;i<=1000;i++)
{
a[i] = a[i%10]+a[i/10];//大佬的奇妙思维,我是真的想不到
}
dfs(1);
cout<<cnt;
}
暴力枚举基本上很多题都要用到dfs,这里先将我这个菜鸡不会做的暴力枚举题列出,dfs等题目再做点,最后来个总结