2020年蓝桥杯模拟赛解题报告(CPP版本)
Dev-C++ 常用快捷键大全
题目
【问题描述】
1200000有多少个约数(只计算正约数)。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
#include
using namespace std;
int main()
{
int n;
scanf("%d", &n);
int r = (int)sqrt(1.0 * n);
int sum = 0;
if(r * r == n)
{
sum++;
r--;
}
for(int i = 1; i <= r; i++)
if(n % i == 0)
{
sum += 2;
}
printf("%d\n", sum);
return 0;
}
#include
using namespace std;
const int N = 1200000;
int main() {
int ans = 0;
for (int i = 1; i <= N; ++i) {
if (N % i == 0)
ans++;
}
cout << ans << endl;
return 0;
}
题目
【问题描述】
一棵包含有2019个结点的二叉树,最多包含多少个叶结点?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
思路
n=n0+n1+n2,为使叶子节点数(n0)最多,必须n1最小,设为0,而n0=n2+1
得n2=(2019-1)/2=1009
所以n0=1010
答案
1010
二叉树的五大性质及证明
【问题描述】
在1至2019中,有多少个数的数位中包含数字9?
注意,有的数中的数位中包含多个9,这个数只算一次。例如,1999这个数包含数字9,在计算时只是算一个数。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
#include
using namespace std;
int main()
{
int sum=0;
for(int i=1;i<=2019;i++)
{
int t=i;
while(t>=1)
{
if(t%10==9){
sum++;
break;
}
t=t/10;
}
}
cout<<sum<<'\n';
return 0;
}
题目
【问题描述】
一个正整数如果任何一个数位不大于右边相邻的数位,则称为一个数位递增的数,例如1135是一个数位递增的数,而1024不是一个数位递增的数。
给定正整数 n,请问在整数 1 至 n 中有多少个数位递增的数?
【输入格式】
输入的第一行包含一个整数 n。
【输出格式】
输出一行包含一个整数,表示答案。
【样例输入】
30
【样例输出】
26
【评测用例规模与约定】
对于 40% 的评测用例,1 <= n <= 1000。
对于 80% 的评测用例,1 <= n <= 100000。
对于所有评测用例,1 <= n <= 1000000。
#include
using namespace std;
int main(){
int n,i,j;
cin>>n;
int sum=0;
char s[7];
for(i=1;i<=n;i++){
sprintf(s,"%d",i);
for(j=1;j<strlen(s);j++){
if(s[j]<s[j-1]){
break;
}
}
if(j==strlen(s)){
sum++;
}
}
cout<<sum<<'\n';
return 0;
}
sprintf用法
题目
【问题描述】
小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
请告诉小明,k 个月后空地上哪些地方有草。
【输入格式】
输入的第一行包含两个整数 n, m。
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。
【输出格式】
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
【样例输入】
4 5
.g…
…
…g…
…
2
【样例输出】
gggg.
gggg.
ggggg
.ggg.
【评测用例规模与约定】
对于 30% 的评测用例,2 <= n, m <= 20。
对于 70% 的评测用例,2 <= n, m <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
#include
using namespace std;
int dirx[4]={-1,1,0,0};
int diry[4]={0,0,-1,1};
struct block{
int x;
int y;
int State;// 0 已计算过 1 未计算
};
int Map[1001][1001];
int main(){
queue <block> q;//队中存放已经有草的地方
int n,m;
int i,j;
memset(Map,0,sizeof(Map));
cin>>n>>m;
char g;
for(i=1;i<=n;i++){ //输入
for(j=1;j<=m;j++){
cin>>g;
if(g=='g'){
block t;
t.x=i;
t.y=j;
t.State=1;
Map[i][j]=1;
q.push(t);
}
}
}
int k,len;
cin>>k;
while(k--){
len=q.size();
for(i=1;i<=len;i++){
block t = q.front();//取队首
if(t.State==1){
for(int u=0;u<=3;u++){
if(t.x+dirx[u]>=1&&t.x+dirx[u]<=n&&t.y+diry[u]>=1&&t.y+diry[u]<=m){// 上下左右方向在范围内
if(Map[t.x+dirx[u]][t.y+diry[u]]==0){
block New;
Map[t.x+dirx[u]][t.y+diry[u]]=1;
New.x=t.x+dirx[u];
New.y=t.y+diry[u];
New.State=1;
q.push(New);
}
}
}
}
q.pop();//将队首出队
t.State=0;
q.push(t);//原先的队首入队尾
}
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(Map[i][j]==1){
cout<<'g';
}
else{
cout<<'.';
}
}
cout<<endl;
}
return 0;
}
#include
using namespace std;
int dirx[4]={-1,1,0,0};
int diry[4]={0,0,-1,1};
struct block{
int x;
int y;
};
int Map[1001][1001];//Map记录已有草的位置
int main(){
queue <block> q;//队中仅存放可继续扩展的有草小块
int n,m;
int i,j;
memset(Map,0,sizeof(Map));
cin>>n>>m;
char g;
for(i=1;i<=n;i++){ //输入
for(j=1;j<=m;j++){
cin>>g;
if(g=='g'){
block t;
t.x=i;
t.y=j;
Map[i][j]=1;
q.push(t);
}
}
}
int k,len;
cin>>k;
while(k--){
len=q.size();
for(i=1;i<=len;i++){
block t = q.front();//取队首
for(int u=0;u<=3;u++){
if(t.x+dirx[u]>=1&&t.x+dirx[u]<=n&&t.y+diry[u]>=1&&t.y+diry[u]<=m){// 上下左右方向在范围内
if(Map[t.x+dirx[u]][t.y+diry[u]]==0){
block New;
Map[t.x+dirx[u]][t.y+diry[u]]=1;
New.x=t.x+dirx[u];
New.y=t.y+diry[u];
q.push(New);
}
}
}
q.pop();//将队首出队 队首所示有草小块四周已拓展完毕
}
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(Map[i][j]==1){
cout<<'g';
}
else{
cout<<'.';
}
}
cout<<endl;
}
return 0;
}
bfs,广度优先搜索,用队列暂存当前有草的所有位置,每过一个月,将先有当前队列中已有元素依次出栈,将新长出来的草块入栈,用矩阵Map记录草块的当前情况。
此法可保证每块草地至多被计算一次,时间复杂度为 O ( N ∗ M ) O(N*M) O(N∗M)。
小明想知道,满足以下条件的正整数序列的数量:
由本题第三点的递归定义,可以得到递归公式:
f ( p r e , c u r ) = f ( c u r , 1 ) + f ( c u r , 2 ) + . . . + f ( c u r , a b s ( p r e − c u r ) + 1 = ∑ i = 1 ∣ p r e − c u r ∣ f ( c u r , i ) + 1 f(pre,cur) = f(cur,1) + f(cur,2) + ...+f(cur,abs(pre-cur)+1 =\sum_{i=1}^{|pre-cur|}f(cur,i) +1 f(pre,cur)=f(cur,1)+f(cur,2)+...+f(cur,abs(pre−cur)+1=i=1∑∣pre−cur∣f(cur,i)+1
(其中 p r e pre pre表示前一个数, c u r cur cur表示当前数。)
时间复杂度: O ( n 3 ) O(n^3) O(n3)
#include
using namespace std;
int sum=0;
void r(int Abs,int now){
sum++;
sum=sum%10000;
for(int i=1;i<Abs;i++){
if(abs(now-i)>=2){
r(abs(now-i),i);
}
else{
sum++;
sum=sum%10000;
}
}
}
int main()
{
int n;
cin>>n;
for(int j=1;j<=n;j++)
{
r(n-j,j);
}
cout<<sum<<'\n';
return 0;
}
Or
#include
using namespace std;
int sum=0;
void r(int Abs,int now){
sum++;
sum=sum%10000;
for(int i=1;i<Abs;i++){
if(abs(now-i)>=2){
r(abs(now-i),i);
}
else{
sum++;
sum=sum%10000;
}
}
}
int main()
{
int n;
cin>>n;
for(int j=1;j<=n;j++)
{
r(n-j,j);
}
cout<<sum<<'\n';
return 0;
}
空间换时间,还是会超时,但已可通过大部分样例。
当 n= 1000时,已可在有限时间内计算出结果。
#include
using namespace std;
int sum=0;
int mem[1010][1010];
int r(int pre,int now){
int num = 1;
if(mem[pre][now]!=0){
return mem[pre][now];
}
for(int i=1;i<abs(pre-now);i++){
num += r(now,i)%10000;
}
mem[pre][now] = num;
return num;
}
int main()
{
int n;
memset(mem,0,sizeof(mem));
cin>>n;
for(int j=1;j<=n;j++)
{
sum = (sum+r(n,j))%10000;
}
cout<<sum<<'\n';
return 0;
}
在上一种情况下, 解的空间是 n 2 n^2 n2,但因为展开循环累加,实际的复杂度还是 n 3 n^3 n3。若可以规避循环累加,则可以将复杂度优化到 n 2 n^2 n2。
重新考虑状态转移,用 f ( i , j ) f(i,j) f(i,j)表示 p r e = i pre =i pre=i,当前数是 1 ∼ j 1\sim j 1∼j时候的合法序列个数。有:
f ( i , j ) = f ( i , j − 1 ) + f ( j , a b s ( i − j ) − 1 ) + 1 f(i,j)=f(i,j-1)+f(j,abs(i-j)-1)+1 f(i,j)=f(i,j−1)+f(j,abs(i−j)−1)+1
这样每次解答树只需要展开两个节点,相当于少一次循环,尽管解答树的层次还是很深,但是有记忆存储的辅助,解空间依然是 n 2 n^2 n2。可以在更短的时间内解决问题。
#include
#define mod 10000
using namespace std;
int sum=0;
int mem[1010][1010];
int r(int now,int sub){
if(sub<=0){
return 0;
}
int num = 0;
if(mem[now][sub]!=0){
return mem[now][sub];
}
int res = r(now,sub-1)%mod+r(sub,abs(now-sub)-1)%mod+1;
mem[now][sub] = res;
return res;
}
int main()
{
int n;
memset(mem,0,sizeof(mem));
cin>>n;
cout<<r(n,n)<<'\n';
return 0;
}
如何判断自己的算法是否超时??
代码敲完后,如果可以,最大样例输入是一样,看能不能在有限的时间内出结果。一般不超时的算法,几秒钟内就可以出结果。