第八届蓝桥杯大赛个人赛省赛(软件类本科B组)(做题笔记)

    科技2022-08-23  122

    标题: 购物单

        小明刚刚找到工作,老板人很好,只是老板夫人很爱购物。老板忙的时候经常让小明帮忙到商场代为购物。小明很厌烦,但又不好推辞。

        这不,XX大促销又来了!老板夫人开出了长长的购物单,都是有打折优惠的。     小明也有个怪癖,不到万不得已,从不刷卡,直接现金搞定。     现在小明很心烦,请你帮他计算一下,需要从取款机上取多少现金,才能搞定这次购物。

        取款机只能提供100元面额的纸币。小明想尽可能少取些现金,够用就行了。     你的任务是计算出,小明最少需要取多少现金。

    以下是让人头疼的购物单,为了保护隐私,物品名称被隐藏了。 ----------------- ****     180.90       88折 ****      10.25       65折 ****      56.14        9折 ****     104.65        9折 ****     100.30       88折 ****     297.15        半价 ****      26.75       65折 ****     130.62        半价 ****     240.28       58折 ****     270.62        8折 ****     115.87       88折 ****     247.34       95折 ****      73.21        9折 ****     101.00        半价 ****      79.54        半价 ****     278.44        7折 ****     199.26        半价 ****      12.97        9折 ****     166.30       78折 ****     125.50       58折 ****      84.98        9折 ****     113.35       68折 ****     166.57        半价 ****      42.56        9折 ****      81.90       95折 ****     131.78        8折 ****     255.89       78折 ****     109.17        9折 ****     146.69       68折 ****     139.33       65折 ****     141.16       78折 ****     154.74        8折 ****      59.42        8折 ****      85.44       68折 ****     293.70       88折 ****     261.79       65折 ****      11.30       88折 ****     268.27       58折 ****     128.29       88折 ****     251.03        8折 ****     208.39       75折 ****     128.88       75折 ****      62.06        9折 ****     225.87       75折 ****      12.89       75折 ****      34.28       75折 ****      62.16       58折 ****     129.12        半价 ****     218.37        半价 ****     289.69        8折 --------------------

    需要说明的是,88折指的是按标价的88%计算,而8折是按80%计算,余者类推。 特别地,半价是按50%计算。

    请提交小明要从取款机上提取的金额,单位是元。 答案是一个整数,类似4300的样子,结尾必然是00,不要填写任何多余的内容。

    特别提醒:不许携带计算器入场,也不能打开手机。 res=5136.86 所以Ans=5200

    Codes: #include <iostream> #include <vector> #include <string.h> #include <sstream>

    using namespace std;

    struct Goods{     double price;     double discount;     double cost;     Goods(){    }     Goods(double pce,double dct):price(pce),discount(dct){         this->cost=pce*dct;     } };

    vector<Goods> vkt;

    double getDscntNum(string discount){     if(discount=="半价")         return 0.5;         string num="";     for(int i=0;i<discount.size()-1;i++){         num+=discount[i];     }         double dnum=stoi(num);         if(dnum>10)         return dnum/100;     else if(dnum<10)         return dnum/10;         }

    int main(int argc, char** argv) {     while(true){         string chr;         double price;         string discount;         cin>>chr;         if(chr=="@")             break;         cin>>price>>discount;         vkt.push_back(Goods(price,getDscntNum(discount)));     }         double total=0;     for(int i=0;i<vkt.size();i++){         total+=vkt[i].cost;     }     cout<<total<<endl;     return 0; }

     

    标题:等差素数列

    2,3,5,7,11,13,....是素数序列。 类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。 上边的数列公差为30,长度为6。

    2004年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。 这是数论领域一项惊人的成果!

    有这一理论为基础,请你借助手中的计算机,满怀信心地搜索:

    长度为10的等差素数列,其公差最小值是多少?

    注意:需要提交的是一个整数,不要填写任何多余的内容和说明文字。 Ans=210

    Codes: #include <iostream> #include <vector> #include <algorithm>

    using namespace std;

    //暴力解法 

    vector<long long> Prime; long long ans=0;

    bool isPrime(long long x){          for(long long i=2;i<=x/2;i++){         if(x%i==0)             return false;     }     return true; }

    long long getMinL(){          for(int i=0;i<Prime.size();i++){         long long start=Prime[i];         for(long long delta=2;delta<=Prime[Prime.size()-1]-start;delta++){             long long sum=start;             for(int j=1;j<10;j++){                 sum+=delta;                 if(find(Prime.begin(),Prime.end(),sum)==Prime.end())                     break;                 if(sum>Prime[Prime.size()-1])                     break;                 if(j==9)                     return delta;             }         }     }          }

    int main(int argc, char** argv) {     //先生成5000个素数          Prime.push_back(2);     Prime.push_back(3);          for(int i=5;;i++){         if(isPrime(i))             Prime.push_back(i);         if(Prime.size()==800)             break;     }           cout<<getMinL()<<endl;          cout<<"hello world!"<<endl;     return 0; }  

    标题:承压计算

    X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。

    每块金属原料的外形、尺寸完全一致,但重量不同。 金属材料被严格地堆放成金字塔形。

                                 7                              5 8                             7 8 8                            9 2 7 2                           8 1 4 9 1                          8 1 8 8 4 1                         7 9 6 1 4 5 4                        5 6 5 5 6 9 5 6                       5 5 4 7 9 3 5 5 1                      7 5 7 9 7 4 7 3 3 1                     4 6 4 5 5 8 8 3 2 4 3                    1 1 3 3 1 6 6 5 5 4 4 2                   9 9 9 2 1 9 1 9 2 9 5 7 9                  4 3 3 7 7 9 3 6 1 3 8 8 3 7                 3 6 8 1 5 3 9 5 8 3 8 1 8 3 3                8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9               8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4              2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9             7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6            9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3           5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9          6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4         2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4        7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6       1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3      2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8     7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9    7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6   5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1  X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 

    其中的数字代表金属块的重量(计量单位较大)。 最下一层的X代表30台极高精度的电子秤。

    假设每块原料的重量都十分精确地平均落在下方的两个金属块上, 最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。 电子秤的计量单位很小,所以显示的数字很大。

    工作人员发现,其中读数最小的电子秤的示数为:2086458231

    请你推算出:读数最大的电子秤的示数为多少?

    注意:需要提交的是一个整数,不要填写任何多余的内容。 Ans=72665192664

    解题思路:本题关键要考虑到,二分重量时整数变小数,从而导致最总电子秤上的读数也为小数,导致 电子秤 倍率计算不精确。 因此,在输入金属块重量时,同时乘以 2^30 ,这样二分质量时就不会 出现小数,最后 计算电子秤 缩小的倍率 才会精确。 最终的 最大示数值= 最大读数*电子秤的倍率(即 最小示数/最小度数 )。

    Codes: #include <iostream> #include <algorithm>

    using namespace std;

    long long G[30][30];

    int main(int argc, char** argv) {          long long factor=1;     for(int i=0;i<30;i++){         factor*=2;     }     for(int i=0;i<29;i++){         for(int j=0;j<=i;j++){             long long a;             cin>>a;             G[i][j]=a*factor;         }     } 

        for(int i=0;i<29;i++){         for(int j=0;j<=i;j++){             long long half=G[i][j]/2;             G[i+1][j]+=half;             G[i+1][j+1]+=half;         }     }               sort(G[29],G[29]+30);         long long minW=G[29][0];     long long maxW=G[29][29];

        cout<<"minW="<<minW/2<<" ,maxW="<<maxW/2<<endl;     return 0; }

    标题:方格分割

    6x6的方格,沿着格子的边线剪开成两部分。 要求这两部分的形状完全相同。

    如图:p1.png, p2.png, p3.png 就是可行的分割法。

    试计算: 包括这3种分法在内,一共有多少种不同的分割方法。 注意:旋转对称的属于同一种分割法。

    请提交该整数,不要填写任何多余的内容或说明文字。

    解题思路:用划线的方式模拟切割方格=>DFS()深搜,模拟分割线的前进:分割线的前端 每前进一个单位,就将它的坐标和 它关于原点(3,3)对称的坐标的访问值vis置为1。当分割线的前端走到边界时,ans++ 并回退到上一步,再将 上一步的 vis[i][j] 和  vis[6-i][6-j] 重置为0。 最终的ans是 遍历了四个 象限的 分割线数量之和。所以最终的分割法=ans/4 。 

    Codes: #include <iostream> #include <string.h>

    using namespace std;

    int vis[7][7]; int dir[][2]{{-1,0},{0,1},{1,0},{0,-1}}; long ans=0;

    void dfs(int x,int y){     if(x==0 || y==0 || x==6 || y==6){         ans++;         return;     }          vis[x][y]=1;          vis[6-x][6-y]=1;          for(int i=0;i<4;i++){         int nx=x+dir[i][0];         int ny=y+dir[i][1];                  if(nx<0 || nx>6 || ny<0 || ny>6)             continue;                  if(vis[nx][ny]==0)             dfs(nx,ny);     }          vis[x][y]=0;     vis[6-x][6-y]=0; }

    int main(int argc, char** argv) {     memset(vis,0,sizeof(vis));     dfs(3,3);     cout<<ans/4<<endl;//结果 ans/4, 去除 翻转的重复次数 

        return 0; }

     

    标题:取数位

    求1个整数的第k位数字有很多种方法。 以下的方法就是一种。

    // 求x用10进制表示时的数位长度  int len(int x){     if(x<10) return 1;     return len(x/10)+1; }      // 取x的第k位数字 int f(int x, int k){     if(len(x)-k==0) return x;     return __________f(x/10,k)___________;  //填空 }      int main() {     int x = 23574;     printf("%d\n", f(x,3));     return 0; }

    对于题目中的测试数据,应该打印5。

    请仔细分析源码,并补充划线部分所缺少的代码。

    注意:只提交缺失的代码,不要填写任何已有内容或说明性的文字。 Ans= f(x/10,k)  

    标题:最大公共子串

    最大公共子串长度问题就是: 求两个串的所有子串中能够匹配上的最大长度是多少。

    比如:"abcdkkk" 和 "baabcdadabc", 可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。

    下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。

    请分析该解法的思路,并补全划线部分缺失的代码。

    #include <stdio.h> #include <string.h>

    #define N 256 int f(const char* s1, const char* s2) {     int a[N][N];     int len1 = strlen(s1);     int len2 = strlen(s2);     int i,j;          memset(a,0,sizeof(int)*N*N);     int max = 0;     for(i=1; i<=len1; i++){         for(j=1; j<=len2; j++){             if(s1[i-1]==s2[j-1]) {                 a[i][j] = ________a[i-1][j-1]+1__________________;  //填空                 if(a[i][j] > max) max = a[i][j];             }         }     }          return max; }

    int main() {     printf("%d\n", f("abcdkkk", "baabcdadabc"));     return 0; }

    注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。 Ans = a[i-1][j-1]+1   

    标题:日期问题

    小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在1960年1月1日至2059年12月31日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。  

    比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。  

    给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

    输入 ---- 一个日期,格式是"AA/BB/CC"。  (0 <= A, B, C <= 9)  

    输入 ---- 输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。多个日期按从早到晚排列。  

    样例输入 ---- 02/03/04  

    样例输出 ---- 2002-03-04   2004-02-03   2004-03-02  

    资源约定: 峰值内存消耗(含虚拟机) < 256M CPU消耗  < 1000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意: main函数需要返回0; 只使用ANSI C/ANSI C++ 标准; 不要调用依赖于编译环境或操作系统的特殊函数。 所有依赖的函数必须明确地在源文件中 #include <xxx> 不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    Codes: #include <iostream> #include <string.h> #include <vector> #include <sstream> #include <algorithm> #include <map>

    using namespace std;

    string date; string AA,BB,CC; vector<string> res; map<string,int> M;

    string Itos(int x){     stringstream is;     is<<x;     return is.str();      }

    int Stoi(string st){     stringstream os(st);     int x;     os>>x;     return x; } void getABC(string date){//现获取A,B,C=>无序 的 年月日      //格式是"AA/BB/CC"。  (0 <= A, B, C <= 9)        string aa,bb,cc;     AA=date.substr(0,2);     BB=date.substr(3,2);     CC=date.substr(6,2); }

    bool isLeap(int yy){     if( (yy%4==0 && yy0!=0) || yy@0==0 )         return true;     return false;      }

    int main(int argc, char** argv) {     cin>>date;

        getABC(date);     //有采用 年/月/日的,有采用 月/日/年的,还有采用 日/月/年的     //这些日期都在 1960年1月1日 至 2059年12月31日     //一个一个试          //若为  年/月/日的     //若有2月,每一次 都要检验是否为闰年,日期是否大于28       if((BB>="01" && BB<="12") && (CC>="01" && CC<="31") ){//月,日的限定条件          string NA,ND;         if(AA>="60"){//20世纪              NA="19"+AA;         }         if(AA<="59"){             NA="20"+AA;         }                               ND=NA+"-"+BB+"-"+CC;         if(!M[ND] && BB=="02" && isLeap(Stoi(NA)) && CC<="29" ){//闰年二月              res.push_back(ND);             M[ND]=1;         }          if( !M[ND] &&BB=="02" && !isLeap(Stoi(NA)) && CC<="28"){//平年二月              res.push_back(ND);              M[ND]=1;         }         if(!M[ND] &&BB!="02"){             res.push_back(ND);             M[ND]=1;         }                       }          //若为 月/日/年的     if( (AA>="01" && AA<="12") && (BB>="01" && BB<="31") ){         string NA,ND;         if(CC>="60"){//20世纪              NA="19"+CC;         }         if(CC<="59"){             NA="20"+CC;         }                               ND=NA+"-"+AA+"-"+BB;              if( !M[ND] &&AA=="02" && isLeap(Stoi(NA)) && BB<="29" ){//闰年二月              res.push_back(ND);             M[ND]=1;          }          if(!M[ND] &&AA=="02" && !isLeap(Stoi(NA)) && BB<="28"){//平年二月              res.push_back(ND);              M[ND]=1;          }         if(!M[ND] &&AA!="02"){             res.push_back(ND);             M[ND]=1;          }     }

        //若为 日/月/年     if( (AA>="01" && AA<="31") && (BB>="01" && BB<="12") ){         string NA,ND;         if(CC>="60"){//20世纪              NA="19"+CC;         }         if(CC<="59"){             NA="20"+CC;         }         ND=NA+"-"+BB+"-"+AA;

            if( !M[ND] &&BB=="02" && isLeap(Stoi(NA)) && AA<="29" ){//闰年二月              res.push_back(ND);             M[ND]=1;          }          if(!M[ND] &&BB=="02" && !isLeap(Stoi(NA)) && AA<="28"){//平年二月              res.push_back(ND);              M[ND]=1;          }         if(!M[ND] &&BB!="02"){             res.push_back(ND);             M[ND]=1;          }              }          sort(res.begin(),res.end());          for(int i=0;i<res.size();i++)         cout<<res[i]<<endl;          return 0; }  

    标题: 分巧克力

        儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。     小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

        为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

        1. 形状是正方形,边长是整数       2. 大小相同  

    例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

    当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

    输入 第一行包含两个整数N和K。(1 <= N, K <= 100000)   以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)  输入保证每位小朋友至少能获得一块1x1的巧克力。   

    输出 输出切出的正方形巧克力最大可能的边长。

    样例输入: 2 10   6 5   5 6  

    样例输出: 2

    资源约定: 峰值内存消耗(含虚拟机) < 256M CPU消耗  < 1000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意: main函数需要返回0; 只使用ANSI C/ANSI C++ 标准; 不要调用依赖于编译环境或操作系统的特殊函数。 所有依赖的函数必须明确地在源文件中 #include <xxx> 不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    Codes: #include <iostream> #include <vector>

    using namespace std;

    struct Choco{     long long Hi,Wi;     Choco(long long hh,long long ww):Hi(hh),Wi(ww){    }     Choco(){    } }; vector<Choco> vkt; long long N,K;

    int FindMaxDividedSide(){     long long thismax=0;     for(long long i=0;i<vkt.size();i++){         long long curS=min(vkt[i].Hi,vkt[i].Wi);//选取 长和宽中的较小值,以便得到方形          thismax=max(curS,thismax);     }     return thismax; }

    void getMaxSideFromEnd(){     long long side=FindMaxDividedSide();     long long tmpK=0;     while(true){         tmpK=0;//当前可获得的正方形巧克力数         for(int i=0;i<vkt.size();i++){             tmpK+= (vkt[i].Hi/side)*(vkt[i].Wi/side);         }          if(tmpK>=K)             break;                  side--;     }     cout<<side<<endl; }

    int main(int argc, char** argv) {     cin>>N>>K;         for(int i=0;i<N;i++){         Choco CO;         cin>>CO.Hi>>CO.Wi;         vkt.push_back(CO);     }     getMaxSideFromEnd();     return 0; }

     

    标题: k倍区间

    给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。  

    你能求出数列中总共有多少个K倍区间吗?  

    输入 ----- 第一行包含两个整数N和K。(1 <= N, K <= 100000)   以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)  

    输出 ----- 输出一个整数,代表K倍区间的数目。  

    例如, 输入: 5 2 1   2   3   4   5  

    程序应该输出: 6

    资源约定: 峰值内存消耗(含虚拟机) < 256M CPU消耗  < 2000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意: main函数需要返回0; 只使用ANSI C/ANSI C++ 标准; 不要调用依赖于编译环境或操作系统的特殊函数。 所有依赖的函数必须明确地在源文件中 #include <xxx> 不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。 解题思路:前缀和 + 同一余数之差%K==0

    AC Codes: #include <iostream> #include <map>   using namespace std;

    long long N,K; long long A[100002];//A[i] :第i项  long long S[100002];//S[i]:前 i 项的和  map<long,long> Index;//Index->first 存放S[i] ; Index-second 存放 S[i] 出现的次数 

    int main(int argc, char** argv) {     cin>>N>>K;               S[0]=0;     Index[0]=1;          for(long long i=1;i<=N;i++){         cin>>A[i];         S[i]=(A[i]+S[i-1])%K;//前缀和 解题 + 同一余数 之差 %K==0;           Index[S[i]]++;     }          long long cnt=0; //    for(long long i=0;i<N;i++){ //         //        for(long long j=i;j<N;j++){ //            long long sum=S[j]-S[i-1]; //            if(sum%K==0){ //                cnt++; //            } //        } //    }          for(int i=0;i<K;i++){//对K取模后的  0 <= S[i] <= k-1           cnt+=(long long)Index[i]*(Index[i]-1)/2;         }          cout<<cnt<<endl;     return 0; }

     

    Processed: 0.017, SQL: 9