2014B组C++
https://www.lanqiao.cn/courses/3993/learning/?id=248897
https://www.lanqiao.cn/courses/5450/learning/?id=245079
啤酒和饮料
题意:
啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。
我们还知道他买的啤酒比饮料的数量少,请你计算他买了几罐啤酒。
注意:答案是一个整数。请通过浏览器提交答案。
不要书写任何多余的内容(例如:写了饮料的数量,添加说明文字等)。
代码
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
for (int i = 1; i <=50 ; ++i) {
for (int j = 1; j <=60 ; ++j) {
if(i<j && 2.3*i+1.9*j==82.3)
cout<<i<<" "<<j<<endl;
}
}
return 0;
}
切面条
题意:
一根高筋拉面,中间切一刀,可以得到2根面条。
如果先对折1次,中间切一刀,可以得到3根面条。
如果连续对折2次,中间切一刀,可以得到5根面条。
那么,连续对折10次,中间切一刀,会得到多少面条呢?
答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。
这道题有点dp思想了,还得找数学规律。
#include<iostream>
using namespace std;
int main()
{
int i,f[50];
f[0]=2;
f[1]=3;
for(i=1;i<=10;i++)
f[i]=2*f[i-1]-1;
printf("%d",f[10]);
return 0;
}
李白打酒
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。
像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。
注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。
代码:递归的思想
#include <iostream>
using namespace std;
int ans;//答案
void f(int dian, int hua, int jiu) {//店 花 酒
if (dian == 0 && hua == 0 && jiu == 1)
ans++;
if (dian > 0)
f(dian - 1, hua, jiu * 2);
if (hua > 0)
f(dian, hua - 1, jiu - 1);
}
int main(int argc, const char *argv[]) {
f(5, 9, 2); //反正最后一次确定了,那就是说,能达到最后一次的序列效果就行,所以这里的花数是9
cout << ans << endl;
return 0;
}
史丰收速算
题意;
/*
标题:史丰收速算
史丰收速算法的革命性贡献是:从高位算起,预测进位。不需要九九表,彻底颠覆了传统手算!
速算的核心基础是:1位数乘以多位数的乘法。
其中,乘以7是最复杂的,就以它为例。
因为,1/7 是个循环小数:0.142857...,如果多位数超过 142857...,就要进1
同理,2/7, 3/7, ... 6/7 也都是类似的循环小数,多位数超过 n/7,就要进n
下面的程序模拟了史丰收速算法中乘以7的运算过程。
乘以 7 的个位规律是:偶数乘以2,奇数乘以2再加5,都只取个位。
乘以 7 的进位规律是:
满 142857... 进1,
满 285714... 进2,
满 428571... 进3,
满 571428... 进4,
满 714285... 进5,
满 857142... 进6
请分析程序流程,填写划线部分缺少的代码。
//计算个位
int ge_wei(int a)
{
if(a % 2 == 0)
return (a * 2) % 10;
else
return (a * 2 + 5) % 10;
}
//计算进位
int jin_wei(char* mod)
{
char* level[] = {
"142857",
"285714",
"428571",
"571428",
"714285",
"857142"
};
char buf[7];
buf[6] = '\0';
strncpy(buf,mod,6); //strncpy函数用于将指定长度的字符串复制到字符数组中,是 C语言的库函数之一,来自 C语言标准库,定义于 string.h。
int i;
for(i=5; i>=0; i--){
int tr = strcmp(level[i], buf);
//strcmp函数是string compare(字符串比较)的缩写,
//用于比较两个字符串并根据比较结果返回整数。
//基本形式为strcmp(str1,str2),
//若str1=str2,则返回零;
//若str1 > str2,则返回正数。
//本题是从最大的开始比较。一开始是level大
if(tr<0) return i+1;
while(tr==0){
mod += 6; //mod是指针
strncpy(buf,mod,6);
tr = strcmp(level[i], buf);
if(tr<0) return i+1;
______________________________; //填空
}
}
return 0;
}
//多位数乘以7
void f(char* s)
{
int head = jin_wei(s); //第一次head=2
if(head > 0) printf("%d", head);
char* mod = s;
while(*mod){
int a = (*mod-'0');
int x = (ge_wei(a) + jin_wei(mod+1)) % 10;
printf("%d",x);
mod++;
}
printf("\n");
}
int main()
{
f("428571428571");
dfs("34553834937543");
return 0;
}
注意:通过浏览器提交答案。只填写缺少的内容,不要填写任何多余的内容(例如:说明性文字)
*/
答案:
if(tr>0) return i;
//这里>=也行,只要能根据题目给的数据弄出正确答案。拿在纸上画一画就行了。
补充:
乘数为2时,口诀为:满五进1;
乘数为3时,口诀为:超3进1,超6进2;
乘数为4时,口诀为:满25进1,满50进2,满75进3;
乘数为5时,口诀为:满2进1,满4进2,满6进3,满8进4;
乘数为6时,口诀为:超16进1,超3进2,满5进3,超6进4,超83进5;
乘数为7时,口诀为:超142857进1,超285714进2,超428571进3,超571428进4,超714285进5,超857142进6;
乘数为8时,口诀为:满125进1,满25进2,满375进3,满5进4,满625进5,满75进6,满875进7;
乘数为9时,口诀为:超1进1,超2进2,超3进3,……超8进8
打印图形
小明在X星球的城堡中发现了如下图形和文字:
/*
rank=3
*
* *
* *
* * * *
rank=5
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
ran=6
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
小明开动脑筋,编写了如下的程序,实现该图形的打印。
#define N 70
void f(char a[][N], int rank, int row, int col)
{
if(rank==1){
a[row][col] = '*';
return;
}
int w = 1;
int i;
for(i=0; i<rank-1; i++) w *= 2;
____________________________________________;
f(a, rank-1, row+w/2, col);
f(a, rank-1, row+w/2, col+w);
}
int main()
{
char a[N][N];
int i,j;
for(i=0;i<N;i++)
for(j=0;j<N;j++) a[i][j] = ' ';
f(a,6,0,0);
for(i=0; i<N; i++){
for(j=0; j<N; j++) printf("%c",a[i][j]);
printf("\n");
}
return 0;
}
请仔细分析程序逻辑,填写缺失代码部分。
通过浏览器提交答案。注意不要填写题目中已有的代码。也不要写任何多余内容(比如说明性的文字)
*/
#include <iostream>
using namespace std;
#define N 70
void f(char a[][N], int rank, int row, int col)
{
if (rank == 1) {
a[row][col] = '*';
return;
}
int w = 1;
int i;
for (i = 0; i < rank - 1; i++)
w *= 2;
// ____________________________________________;
f(a, rank - 1, row , col+w/2);//a,5,0,16,处理顶上的三角形
f(a, rank - 1, row + w / 2, col);//a,5,16,0,处理左下角
f(a, rank - 1, row + w / 2, col + w);//a,5,16,16,处理右下角
}
//--------------=============================================================================
int main()
{
char a[N][N];
int i, j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++) a[i][j] = ' ';
f(a, 5, 0, 0);
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) printf("%c", a[i][j]);
printf("\n");
}
return 0;
}
还是数学找规律嗷
奇怪的分式
题意:
上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:
1/4 乘以 8/5
小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png)
老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!
对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?
请写出所有不同算式的个数(包括题中举例的)。
显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。
但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!
注意:答案是个整数(考虑对称性,肯定是偶数)。请通过浏览器提交。不要书写多余的内容。
代码:(这只是测试函数)
#include <iostream>
using namespace std;
int ans;
int gcd(int a, int b) //最大公约数函数
{
if (b == 0)
return a;
return gcd(b, a % b);
}
int main(int argc, const char *argv[])
{
cout << gcd(12, 16) << endl;
for (int a = 1; a < 10; ++a) //++a比a++ 节省时间
{
for (int b = 1; b < 10; ++b)
{
if (b == a)continue;//a和b是第一个分子分母
for (int c = 1; c < 10; ++c)
{
for (int d = 1; d < 10; ++d)
{
if (c == d) continue; //c和d是第二个分子分母
int g1 = gcd(a * c, b * d);
int g2 = gcd(a * 10 + c, b * 10 + d);//因为拼接完总有一个数是在 十位上的,a * 10 + c表示拼接成的数
if (a * c / g1 == (a * 10 + c) / g2 && b * d / g1 == (b * 10 + d) / g2)
{
printf("%d %d %d %d\n", a, b, c, d);
ans++;
}
}
}
}
}
cout << ans << endl;
return 0;
}
六角填数
题意:
如图【1.png】所示六角形中,填入1~12的数字。
使得每条直线上的数字之和都相同。
图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?
请通过浏览器提交答案,不要填写多余的内容。
代码:
#include <iostream>
#include <vector>
#include <algorithm> //next_permutation在当前序列中,从尾端向前寻找两个相邻元素,前一个记为*i,后一个记为*t,并且满足*i < *t。然后再从尾端
//寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第t个元素之后(包括t)的所有元素颠倒排序,即求出下一个序列了。
//#include <string>
using namespace std;
void check(vector<int> v);
int main(int argc, const char *argv[]) {
vector<int> v;
v.push_back(2); //将2添加到当前数组的最后元素的后面
//因为3已经填进去了
for (int i = 4; i <= 7; ++i) {
v.push_back(i);
}
//8也已经填进去了
for (int i = 9; i <= 12; ++i) {
v.push_back(i);
}
do {
check(v); //实现在下边
} while (next_permutation(v.begin(), v.end()));//变为下一个字母序更大的排列。
return 0;
}
void check(vector<int> v) {
int r1 = 1 + v[0] + v[3] + v[5];
int r2 = 1 + v[1] + v[4] + v[8];
int r3 = 8 + v[0] + v[1] + v[2];
int r4 = 11 + v[3] + v[6];
int r5 = 3 + v[2] + v[4] + v[7];
int r6 = v[5] + v[6] + v[7] + v[8];
if (r1 == r2 && r2 == r3 && r3 == r4 && r4 == r5 && r5 == r6) {
for (int i = 0; i < 9; ++i) {
cout << v[i] << " " << endl;
}
}
}
/*
*号是v[3]=10
*/
参考博客:https://www.freesion.com/article/1501182925/
蚂蚁感冒
长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,
有的朝右。(假设是水平横放在你面前)
每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。
当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,
会把感冒传染给碰到的蚂蚁。
请你计算,当所有蚂蚁都爬离杆子时,
有多少只蚂蚁患上了感冒。
【数据格式】
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。
接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100),
Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。
正值表示头朝右,负值表示头朝左,数据中不会出现0值,
也不会出现两只蚂蚁占用同一位置。
其中,第一个数据代表的蚂蚁感冒了。
要求输出1个整数,表示最后感冒蚂蚁的数目。
例如,输入:
3
5 -2 8
程序应输出:
1
再例如,输入:
5
-10 8 -20 12 25
程序应输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
代码
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
int n;
scanf("%d",&n);
int arr[n];
for (int i = 0; i < n; ++i)
{
scanf("%d",&arr[i]);
}
int x = arr[0];//第一个是感冒的
if(x>0)
{//向右
int ans=1;
for (int i = 0; i < n; ++i) //n只蚂蚁
{
if(arr[i]<0 && -arr[i]>x)//从右向左
ans++;
}
if(ans!=1)//有从右到左
for (int i = 0; i < n; ++i)
{
if(arr[i]>0&&arr[i]<x)//从右向左
ans++;
}
printf("%d\n",ans);
}
if(x<0)
{//向左
// 左侧从左到右的
int ans=1;
for (int i = 0; i < n; ++i)
{
if(arr[i]>0&&arr[i]<-x) //arr[i]在x的左边
ans++;
}
if(ans!=1)
for (int i = 0; i < n; ++i)
{
if(arr[i]<0&&-arr[i]>-x) //x掉头后在x的右边
ans++;
}
printf("%d\n",ans);
}
return 0;
}
其实就是通过数值的比较得出蚂蚁的相对位置,如果向左走的左边还有蚂蚁向右走,那肯定撞上,反之亦然。
地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
【数据格式】
输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
例如,输入:
2 2 2
1 2
2 1
程序应该输出:
2
再例如,输入:
2 3 2
1 2 3
2 1 5
程序应该输出:
14
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>
, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int MOD = 1000000007;
int n, m, k;
int data[50][50];
long long ans;
long long cache[50][50][14][13];
void dfs(int x, int y, int max, int cnt) {
if (x == n || y == m || cnt > k)
return;
int cur = data[x][y];
if (x == n - 1 && y == m - 1)//已经面临最后一个格子
{
if (cnt == k || (cnt == k - 1 && cur > max)) {
ans++;
if (ans > MOD)
ans %= MOD;
}
}
if (cur > max) {//可以取这个物品
dfs(x, y + 1, cur, cnt + 1);
dfs(x + 1, y, cur, cnt + 1);
}
//对于价值较小,或者价值大但不去这个物品的情况如下
dfs(x, y + 1, max, cnt);
dfs(x + 1, y, max, cnt);
}
long long dfs2(int x, int y, int max, int cnt) {
// 查缓存
if (cache[x][y][max+1][cnt] != -1)
return cache[x][y][max+1][cnt];
long long ans = 0;
if (x == n || y == m || cnt > k)
return 0;
int cur = data[x][y];
if (x == n - 1 && y == m - 1)//已经面临最后一个格子
{
if (cnt == k || (cnt == k - 1 && cur > max)) {
ans++;
if (ans > MOD)
ans %= MOD;
}
return ans;
}
if (cur > max) {//可以取这个物品
ans += dfs2(x, y + 1, cur, cnt + 1);
ans += dfs2(x + 1, y, cur, cnt + 1);
}
//对于价值较小,或者价值大但不去这个物品的情况如下
ans += dfs2(x, y + 1, max, cnt);
ans += dfs2(x + 1, y, max, cnt);
cache[x][y][max+1][cnt]=ans % MOD;
return cache[x][y][max+1][cnt];
}
int main(int argc, const char *argv[]) {
scanf("%d %d %d", &n, &m, &k);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
scanf("%d", &data[i][j]);
}
}
// dfs(0, 0, -1, 0);//第一个点的价值可能是0
// printf("%d\n", ans);
memset(cache,-1, sizeof(cache));
printf("%lli\n", dfs2(0, 0, -1, 0));
return 0;
}
小朋友排队
题意:
n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。
当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
【数据格式】
输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
例如,输入:
3
3 2 1
程序应该输出:
9
【样例说明】
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
【数据规模与约定】
对于10%的数据, 1<=n<=10;
对于30%的数据, 1<=n<=1000;
对于50%的数据, 1<=n<=10000;
对于100%的数据,1<=n<=100000,0<=Hi<=1000000。
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>
, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int lowbit(int n) {
return n - (n & (n - 1));
}
/**
* 原始数组的i位置增加v后,更新c数组
* @param i
* @param v
* @param c
*/
void updata(int n, int i, int v, int c[]) {
for (int k = i; k <= n; k += lowbit(k)) {
c[k] += v;
}
}
int getSum(int c[], int i) {
int sum = 0;
for (int k = i; k >= 1; k -= lowbit(k)) {
sum += c[k];
}
return sum;
}
int h[100000];
long long cnt[100000];//记录每个孩子的交换次数
int c[1000000 + 1];
int main(int argc, const char *argv[]) {
// int arr[]={1,2,3,4,5,6,7,8};
// int c[9];
// memset(c,0, sizeof(c));
// for (int i = 0; i < 8; ++i) {
// updata(9,i+1,arr[i],c);
// }
// cout<<getSum(c,5)<<endl;
// cout<<getSum(c,6)<<endl;
// cout<<getSum(c,7)-getSum(c,4)<<endl;
// freopen("/Users/zhengwei/Desktop/其他/input8 (1).txt", "r", stdin);
int n;
scanf("%d", &n);
// memset(cnt,0,sizeof(cnt));
int maxH = -1;
for (int i = 0; i < n; ++i) {
scanf("%d", &h[i]);
if (h[i] > maxH)maxH = h[i];
}
for (int i = 0; i < n; ++i) {
updata(maxH + 1, h[i] + 1, 1, c);//在响应位置计数变为1,其实就是用树状数组维护数据出现的个数
//
int sum = getSum(c, h[i] + 1);//小于等于h[i]+1的数据的个数
cnt[i] += (i + 1) - sum;//得到的就是当前数据左侧比数据大的数的个数
}
memset(c, 0, sizeof(c));
for (int i = n - 1; i >= 0; --i) {
updata(maxH + 1, h[i] + 1, 1, c);//在响应位置计数变为1,其实就是用树状数组维护数据出现的个数
//
// int sum = getSum(c, h[i] + 1);//小于等于h[i]+1的数据的个数
// int self = getSum(c,h[i]+1)-getSum(c,h[i]);
// cnt[i] += sum-self;//上一步求出小于等于h的个数,扣掉自己的个数,得到的就是当前数据右侧比数据小的数的个数
cnt[i] += getSum(c, h[i]);//求出小于h[i]+1 的数据的个数
}
long long ans = 0;
for (int i = 0; i < n; ++i) {
ans += (cnt[i] * (cnt[i] + 1) / 2);
}
printf("%lli\n", ans);
return 0;
}
总结
01 啤酒与饮料 简单枚举
02 切面条 思维,归纳,找规律
03 李白打酒 递归搜索所有的解
*04 史丰收速算
05 打印图形 递归,整体思维
06 奇怪的分式 枚举+最大公约数
07 六角填数 全排列
**08 蚂蚁感冒 思维(穿过身体)
**09 地宫取宝 搜索-》记忆型递归
***10 小朋友排队 树状数组