一、试题A:购物单

二、试题B:等差素数列

三、试题C:承压计算

四、试题D:方格分割

五、试题E:取数位

六、试题F:最大公共子串

七、试题G:日期问题

八、试题H:包子凑数

九、试题I:分巧克力

十、试题J:k倍区间

一、试题A:购物单

在这里插入图片描述

-----------------
****     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,不要填写任何多余的内容。

特别提醒:不许携带计算器入场,也不能打开手机。

解题思路:

  1. 先用记事本把****去掉,9折换成90之类的
  2. 用Excel或者程序来计算

代码如下:

#include<iostream>

using namespace std;

double a,b,c;

int main() { 
    for(int i = 1; i <= 50; i ++ ){
        cin >> a >> b;
        c += a * b / 100;
    }
    cout<<c;    
    return 0;
}

二、试题B:等差素数列

在这里插入图片描述

解题思路:

模拟题

  1. 首先把素数列表求出来
  2. 枚举素数、公差
  3. 满足长度为10,取最小的公差

代码如下:

#include<iostream>

using namespace std;

#define inf 0x3f3f3f3f

const int N = 1e5 + 10;
bool is_prime[N];
int prime[N];
int cnt;
bool st[N];
int ans = inf,dist;

void get_primes(){
    for(int i = 2; i <= N; i ++ ){
        if(!st[i]){
            is_prime[i] = true;
            prime[cnt ++ ] = i;
            for(int j = i + i; j <= N; j += i ){
                st[j] = true;
            }
        }
    }
}

int main() { 
    get_primes(); 
    for(int i = 0; i < cnt; i ++ ){
        int d;
        for(d = 1; d <= 10005; d ++ ){
            bool flag = false;
            int len = 1;int sum = prime[i];
            while(!flag){
                if(is_prime[sum + d]){
                    len ++;sum += d;
                    if(len == 10) flag = true;
                }else{
                    break;
                }
            }
            if(flag) break;
        }
        ans = min(ans,d);
    }
    cout<<ans;
    return 0;
}

三、试题C:承压计算

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

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

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

题目解读:

  1. 所有的金属块的重量都严格精确地平分落在最底层的电子秤上
  2. 读数最小的电子秤的示数为:2086458231

坑点:我们算出来的是金属块的重量,而不是电子秤的示数,所以需要转换一下

在这里插入图片描述

代码如下:

#include<iostream>

using namespace std;

#define inf 0x3f3f3f3f

const int N = 40;
double a[N][N];

int main() { 
    for(int i = 1; i <= 29; i ++ ){
        for(int j = 1; j <= i; j ++) {
            cin >> a[i][j];
        }
    }
    for(int i = 2; i <= 30; i ++ ){
        for(int j = 1; j <= i; j ++ ){
            a[i][j] += a[i-1][j-1]/2 + a[i-1][j]/2;
        }
    }
    double minn = inf,maxx = -inf;
    for(int i = 1; i <= 30; i ++){
        minn = min(a[30][i],minn);
        maxx = max(a[30][i],maxx);
    }
    printf("%lf\n",2086458231/minn*maxx);
    return 0;
}

四、试题D:方格分割

在这里插入图片描述

图一:

在这里插入图片描述

图二:

在这里插入图片描述

图三:

在这里插入图片描述

解题思路:

DFS

  1. 本题要求分割成两块完全相同
  2. 从中心开始对称分割
  3. 下面两种分法算一种,它自身旋转也算一种,所以答案要除以4
    在这里插入图片描述
    在这里插入图片描述

代码如下:

#include<iostream>

using namespace std;

#define inf 0x3f3f3f3f

const int N = 10;

int ans;
bool st[N][N];
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};


void dfs(int x,int y){
    if(x == 0 || y == 0 || x == 6 || y == 6){
        ans ++;
        return ;
    }
    for(int i = 0; i < 4; i ++ ){
        int a,b,c,d;
        a = x + dx[i];
        b = y + dy[i];
        c = 6 - a; d = 6 - b;
        if(a < 0 || a > 6 || b < 0 || b > 6 || c < 0 || c > 6 || d < 0 || d > 6) continue;
        if(st[a][b]) continue;
        st[a][b] = st[c][d] = true;
        dfs(a,b);
        st[a][b] = st[c][d] = false;
    }
}
int main() { 
    st[3][3] = true;
    dfs(3,3);    
    cout<<ans/4;    
    return 0;
}

五、试题E:取数位

标题:取数位

求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%10;
    return _____________________;  //填空
}

int main()
{
    int x = 23574;
    printf("%d\n", f(x,3));
    return 0;
}

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

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

注意:只提交缺失的代码,不要填写任何已有内容或说明性的文字。

水题:f(x/10,k)

六、试题F:最大公共子串(待补)

标题:最大公共子串

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

比如:"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] = __________________________;  //填空
                if(a[i][j] > max) max = a[i][j];
            }
        }
    }

    return max;
}

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

注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。

七、试题G:日期问题(待补)

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

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

八、试题H:包子凑数

标题:包子凑数
小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。

输入

第一行包含一个整数N。(1 <= N <= 100)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100)

输出

一个整数代表答案。如果凑不出的数目有无限多个,输出INF。

例如,
输入:

2  
4  
5   

程序应该输出:

6  

再例如,
输入:

2  
4  
6    

程序应该输出:

INF

解题思路:

扩展欧几里得算法

  1. 若两数互质则两数不能组合的最大值为a * b - a - b。 根据题意 Ai<=100,所以开数组的大小要 > 100*99-100-99
  2. 如果满足所有数的最大公约数不为1则有无穷个,否则都是有限个
  3. 用一个数组标记所有能取到的情况
#include<iostream>

using namespace std;

const int N = 1e4 + 10;

#define inf 0x3f3f3f3f

int n,x,g;
bool st[N + 110];
int ans;

int gcd(int a,int b){
    if(b == 0){
        return a;
    }
    return gcd(b,a%b);
} 
int main() { 
    cin >> n;
    st[0] = true;
    for(int i = 0; i < n; i ++ ){
        cin >> x;
        if(!i) g = x;
        else g = gcd(g,x);
        for(int j = 0; j< N; j ++){
            if(st[j]) st[j + x] = true;
        }
    }    
    if(g != 1){
        cout<<"INF\n";
    }else{
        for(int i = 0; i < N; i ++ ){
            if(!st[i]) ans++;
        }
        cout<<ans;
    }    
    return 0;
}

九、试题I:分巧克力

在这里插入图片描述
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

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

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

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

解题思路:

  1. 每块巧克力有两条边(两个属性),用结构体存储N个巧克力
  2. 分解巧克力:长分解为n个、宽分解为m个,一共有n*m个

方法一:暴力求解

  • 因为题中说了:输入保证每位小朋友至少能获得一块1x1的巧克力。
  • 枚举最大的边N到最小的边1,可以分就结束
#include<iostream>

using namespace std;

const int N = 1e5 + 10;

int n,k;
int ans;
struct Node{
    int x,y;
}node[N];

int main() { 
    scanf("%d %d",&n,&k);
    for(int i = 0; i < n; i ++ ){
        scanf("%d %d",&node[i].x,&node[i].y);
    }
    for(ans = N; ans >= 1; ans --){
        int cnt = 0;
        for(int i = 0; i < n; i ++ ){
            cnt += (node[i].x/ans) * (node[i].y/ans);
        }
        if(cnt >= k){
            cout<<ans;
            break;
        }
    }
    return 0;
}

方法二:二分法

  • 这是一道很明显的二分题
  • 范围在(1,1e5)之间取最大的边
#include<iostream>

using namespace std;

const int N = 1e5 + 10;

int n,k;
int ans;
struct Node{
    int x,y;
}node[N];

bool check(int m){
    int cnt = 0;
    for(int i = 0; i < n; i ++ ){
        cnt += (node[i].x / m) * (node[i].y / m);
    }
    if(cnt >= k) return true;
    return false;
} 
int main() { 
    scanf("%d %d",&n,&k);
    for(int i = 0; i < n; i ++ ){
        scanf("%d %d",&node[i].x,&node[i].y);
    }
    int l = 1, r = 1e5;
    while(l < r){
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;//偏右半边
        else r = mid - 1; 
    }
    cout << l;
    return 0;
}

十、试题J:k倍区间(待补)