蓝桥杯练习笔记(九)

蓝桥杯练习笔记(九)

一、

在这里插入图片描述

测试用例:

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3
  • 看到一个难得用DFS而不是暴力求解的题解:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int sq[100]={5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7, 5, 9, 5, 0,
3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9, 2,7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9,
4, 4, 6, 8, 6, 3, 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1,
4, 0, 1,0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3};
int ans=0;
int datesq[8];       /* 遍历2023年365个日期,将每个日期(8个数字)存入数组中,并试图在sq表里对应寻找 */
int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};   /* 1-12序号是对应月份的对应天数 */

/* dfs深搜的作用是,将存入到datesq里的日期,从第一位数字开始依次往后,在sq表里找相同数字 */
int dfs(int sq[], int datesq[], int pos1, int pos2)
{                             
    if(pos2==8){     /* 当datesq的位置到第八位时,即数组序号0-7已全部找到,即那个日期的每位数组已经找到*/
         return 1;
    }
    if(pos1>=100){
        return 0;     /* 当在sq表查找到100还没有pos2==8时,即那个日期找不到*/
    }
    if(sq[pos1]==datesq[pos2]){
         dfs(sq,datesq,pos1+1,pos2+1); /* 若找到对应数字,开始寻找日期下一位,sq继续遍历 */
    }
    else{
          dfs(sq,datesq,pos1+1,pos2);  /* 没找到对应数字,继续寻找日期这一位但sq继续遍历 */ 
    }
    
}   
int main(int argc, char *argv[])
{
     datesq[0]=2,datesq[1]=0,datesq[2]=2,datesq[3]=3;
     int temp1,temp2,temp3,temp4;
     int mm,dd,yyyy;
     int i,j,x,y;
     for(mm=1;mm<=12;mm++){
         temp1=mm/10;       /* 分解出月份包含的两个数字 */
         temp2=mm%10;
         datesq[4]=temp1,datesq[5]=temp2;
         for(dd=1;dd<=day[mm];dd++){
             x=0,y=0;
             temp3=dd/10;       /* 分解出日期所包含的两个数字 */
             temp4=dd%10;
             datesq[6]=temp3,datesq[7]=temp4;    /* 将日期存入datesq数组里*/
             if(dfs(sq,datesq,x,y)){
                 ans++;
             }
         }
     }
    
    printf("%d",ans);
    
    return 0;
}

这里的思想是将这一年的日期都枚举一遍,然后再在线地对每个日期进行DFS搜索。

  • 暴力解法:
#include <stdio.h>

int main() {
    int array[100] = {
        5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,
        5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,
        2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6, 8, 6, 3, 3,
        8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6,
        1, 4, 0, 1, 0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3
    };

    int daysInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int ans = 0;

    for (int month = 1; month <= 12; ++month) {
        for (int day = 1; day <= daysInMonth[month]; ++day) {
            int dateSeq[8] = {2, 0, 2, 3, month / 10, month % 10, day / 10, day % 10};
            int k = 0;

            for (int i = 0; i < 100; ++i) {
                if (array[i] == dateSeq[k]) {
                    ++k;
                    if (k == 8) {
                        ans++;
                        break;
                    }
                }
            }
        }
    }

    printf("%d\n", ans);
    return 0;
}
  • 还有使用逆向思维的:判断数列中是否含有被查找的日期
a='5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3'
ans=0
def jug(x):
    x1=x%100
    x2=(x//100) % 100
    if(x1>31 or x1<1):
        return False
    if(x2==4 or x2==6 or x2==9 or x2==11):
        if(x1 >30):
            return False
    if(x2==2 and x1>28):
        return False
    return True
for i in range(20230101,20231232):
    if(jug(i)):
        tmp,chk=0,0
        for j in a:
            if(j==str(i)[tmp]):
                tmp+=1
                if(tmp>7):
                    chk=1
                    break
        if(chk==1):
            ans+=1
            continue
print(ans)

二、

在这里插入图片描述

  • 动态规划题解:
#include <iostream>
#include <cstring>
using namespace std;
int dp[31][100];  //dp[i][j]表示做完第i题,得分为j的方案数
int main(){

int res=0;
dp[1][0]=dp[1][10]=1;
for(int i=2 ; i<=30 ; i++)
  for(int j=0 ; j<=90 ; j+=10){ //这里不枚举到100的原因是,这种情况不存在,因为是以70分结束的,100分一定会结束,而80,90分不一定结束
    if(j==0){
      //第i题未做对,方案数为做完第i-1题所有方案数之和 
      for(int k=0 ; k<=90 ; k+=10)
        dp[i][0] += dp[i-1][k];
    }
    else{
      dp[i][j] = dp[i-1][j-10];  //第i题做对 
      if(j == 70) res+=dp[i][j];
    } 
  }
cout<<res;
return 0;
}
  • 还有用记忆化搜索的:
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> mp(35, vector<int>(110, -1));
int dfs(int i, int score){
  if(i < 0 || score == 100)return 0;
  if(mp[i][score] != -1)return mp[i][score];
  if(score == 70) return mp[i][score] = dfs(i - 1, 80) + dfs(i - 1, 0) + 1;
  return mp[i][score] = dfs(i - 1, score + 10) + dfs(i - 1, 0);
}
int main()
{
  cout<<dfs(30, 0);
  return 0;
}

记忆化搜索相较于动态规划而言思维难度有所上升。
能动态规划解决的问题记忆化搜索都能解决,但反过来不一定。因为记忆化搜索的本质就是将深度优先搜索的过程,通过避免重复计算同一个状态的结果,从而将时间复杂度优化到多项式复杂度。

三、

在这里插入图片描述

  • 暴力模拟:
#include <iostream>
using namespace std;
#include<math.h>
typedef long long ll;
int main()
{
    int n = 23333333;
  

    // 请在此输入您的代码
    for (int i = 1;i < n;i++)
    {
      double  x0 = i * 1.0 / n;
       double x1 = (n - i) * 1.0 / n;
       double ans = 0;
         ans -= i * x0 * log2(x0) + (n - i) * x1 * log2(x1);
        if (fabs(ans - 11625907.5798) < 0.0001)
        {
            cout << i << endl;
            break;
        }
    }

    return 0;
}

abs()函数是对整数取绝对值的函数,对浮点数取绝对值的函数是fabs()
对于定值的模拟可以用这种极限的思想取模拟,作差小于0.0001就认为相等。

四、

在这里插入图片描述

  • 这里放上官网排在第一的题解:
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

//获取[1...x]中 4的倍数 和 奇数的个数,前者下取整,后者上取整
LL get_sum(LL x)
{
    return x / 4 + (x + 1) / 2;
}

int main()
{
    LL l, r;
    cin >> l >> r;
    
    cout << get_sum(r) - get_sum(l - 1); //减去集合重合的部分即可
    return 0;
}

这里要先进行数学上的化简才能进行处理。(题解主人:Tomato)(蓝桥官网)

在这里插入图片描述

五、

在这里插入图片描述
在这里插入图片描述

注意这个题不是用动态规划,因为它这个不是算子序列的问题,只是伪装起来的模拟类问题。因为子序列内部的位置也能换的,换了之后是算成两个不同的情况,但这个题里只要位置和长度一样就统统只算一种情况。
所以直接模拟就好,我们找到规律,只要子序列里左边的数大于右边的数,那么交换之后就一定能够满足题意。

#include <iostream>
#include <cstring>
using namespace std;
int cnt=0;
string a;
/*'9'依然比‘3’大   /*双指针法*/
void pan(int i,int j) {
    while(a[i]==a[j]&&i<j) {
        i++;
        j--;
    }
    if(i>=j)return;
    if(a[i]>a[j])cnt++;
    return;
}
int main() {
    getline(cin,a);
    int n=a.size();
    for(int i=0; i<n-1; i++) {
        for(int j=i+1; j<n; j++) {
            pan(i,j);
        }
    }
    cout<<cnt;
    return 0;
}
  • 17
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值