一、试题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,不要填写任何多余的内容。
特别提醒:不许携带计算器入场,也不能打开手机。
解题思路:
- 先用记事本把****去掉,9折换成90之类的
- 用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:等差素数列
解题思路:
模拟题
- 首先把素数列表求出来
- 枚举素数、公差
- 满足长度为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
请你推算出:读数最大的电子秤的示数为多少?
注意:需要提交的是一个整数,不要填写任何多余的内容。
题目解读:
- 所有的金属块的重量都严格精确地平分落在最底层的电子秤上
- 读数最小的电子秤的示数为: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
- 本题要求分割成两块完全相同
- 从中心开始对称分割
- 下面两种分法算一种,它自身旋转也算一种,所以答案要除以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
不能通过工程设置而省略常用头文件。
提交程序时,注意选择所期望的语言类型和编译器类型。
代码如下:
模拟:
#include<iostream>
using namespace std;
int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool isleap(int n) {
if(n % 400 == 0) return true;
if(n % 100 != 0 && n % 4 == 0) return true;
return false;
}
void work(int y,int m,int d){
bool flag = false,ans = true;
if(y >= 0 && y <= 59){
flag = true;
}
if(flag) y += 2000;
else y += 1900;
if(m < 1 || m > 12){
ans = false;
}
if(d < 1 || d > 31){
ans = false;
}
if(m == 2){
if(isleap(y)){
if(d > 29) ans = false;
}else{
if(d > 28) ans = false;
}
}
if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12){
if(d > 31) ans = false;
}else{
if(d > 30) ans = false;
}
if(ans) printf("%d-%02d-%02d\n",y,m,d);
}
int main() {
int y,m,d;
scanf("%d/%d/%d",&y,&m,&d);
if(y == m && m == d) {
work(y,m,d);
return 0;
}
if(y < d) {
work(y,m,d);
if(y < m) {
work(d,y,m);
work(d,m,y);
} else if(y == m){
work(d,m,y);
}else{
work(d,m,y);
work(d,y,m);
}
return 0;
} else {
if(y < m) {
work(d,y,m);
work(d,m,y);
}else if(y == m){
work(d,m,y);
}else{
work(d,m,y);
work(d,y,m);
}
work(y,m,d);
return 0;
}
return 0;
}
八、试题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
解题思路:
扩展欧几里得算法
- 若两数互质则两数不能组合的最大值为a * b - a - b。 根据题意 Ai<=100,所以开数组的大小要 > 100*99-100-99
- 如果满足所有数的最大公约数不为1则有无穷个,否则都是有限个
- 用一个数组标记所有能取到的情况
#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
不能通过工程设置而省略常用头文件。
提交程序时,注意选择所期望的语言类型和编译器类型。
解题思路:
- 每块巧克力有两条边(两个属性),用结构体存储N个巧克力
- 分解巧克力:长分解为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;
}