🎉🎉 目前持续总结更新,请持续关注!!! 🎉🎉
💗 大家好🤗🤗🤗,我是左手の明天!💗
📆 最近更新:2022 年 4 月 19 日,左手の明天的第 230 篇原创博客
🥇 更新于专栏:蓝桥杯预备营
🌟🌟 往期必看 🌟🌟
【蓝桥杯预备营集结一】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结二】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结三】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结四】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结五】第十三届蓝桥杯模拟赛 C/C++ 试题分析及解答
【蓝桥杯预备营集结六】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结七】软件类 C/C++ 预备试题(分支结构+循环结构类)分析及解答
【蓝桥杯预备营集结八】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结九】软件类 C/C++ 预备试题分析及解答
【蓝桥杯预备营集结十】软件类 C/C++ 预备试题分析及解答
🚩切面条目录
🚩切面条
🚩李白打酒
🚩史丰收速算
🚩六角填数
🚩蚂蚁感冒
🚩地宫取宝
🚩小朋友排队
👍👍👍👍👍👍
🌟🌟 预祝各位在每一届中能够得到好的名次 🌟🌟
⭐️问题描述
一根高筋拉面,中间切一刀,可以得到 2 根面条。
如果先对折 1 次,中间切一刀,可以得到 3 根面条。
如果连续对折 2 次,中间切一刀,可以得到 5 根面条。
那么,连续对折 10 次,中间切一刀,会得到多少面条呢?
⭐️题目分析
找规律题目,随便拿张纸对折一下,就得到了对折3次,从中间切一刀,可以得到9根面条,
规律就是An = (An-1)*2-1,A1=2;
或者说是2^n+1。
⭐️代码
#include
using namespace std;
int main()
{
int f[10];
f[1]=3;
for(int i=2;i<11;i++)f[i]=f[i-1]*2-1;//等同(f[i-1]-1)*2+1
cout<
⭐️结果
答案:1025
🚩李白打酒
⭐️问题描述
话说大诗人李白,一生好饮。幸好他从不开车。 一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。
⭐️思路分析
主要介绍两种方法:简单递归,全排列
⭐️方法一:简单递归
#include
using namespace std;
int sum = 0;
void f(int a, int b, int c)
{
if(a > 0)
f(a-1, b, c*2);//不懂的,自己画画图就明白了,跟全排列差不多
if(b > 0)
f(a, b-1, c-1);
if(a==0 && b==0 && c==1) //c==1,由于最后一次是遇花,还未减去1,此时判断的结果刚好是李白喝完酒了
sum += 1;
}
int main()
{
f(5, 9, 2);//遇店a,遇花b,斗酒c(为何b=9?由于最后一次是遇花,不用考虑在内,否则要排除不是遇花的情况)
cout << sum << endl;
return 0;
}
⭐️方法二:全排列
引入< algorithm>标准头文件,调用next_permutation(),最后排序后的数列是递减的。所以数组a中元素必须要递增写,否则不能罗列所有排列。
#include
#include
using namespace std;
int main()
{
int a[15]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,2,2,2,2};//-1遇花,2遇店
int n = 0;//记录总数
do{
int sum = 2; //初始斗酒数
for(int i=0; i<15; i++){
if(a[i] == -1){
sum += a[i];
}else{
sum *= a[i];
}
}
if(a[14]==-1&&sum==0){ //a[14]最后一次是遇花
n +=1;
}
}while(next_permutation(a,a+15));//全排列
cout<< n << endl;
return 0;
}
⭐️结果
运行结果
ababbbbbabababb
abbabbabbbababb
abbabbbaabbbabb
abbabbbabaabbbb
abbbaabbabbbabb
abbbaabbbaabbbb
abbbabaabbabbbb
baababbbbbababb
baabbabbabbbabb
baabbabbbaabbbb
baabbbaabbabbbb
babaababbbbbabb
babaabbabbabbbb
bababaababbbbbb
14
🚩史丰收速算
⭐️问题描述
史丰收速算法的革命性贡献是:从高位算起,预测进位。不需要九九表,彻底颠覆了传统手算!
速算的核心基础是:1位数乘以多位数的乘法。
其中,乘以7是最复杂的,就以它为例。
因为,1/7 是个循环小数:0.142857…,如果多位数超过 142857…,就要进1
同理,2/7, 3/7, … 6/7 也都是类似的循环小数,多位数超过 n/7,就要进n。
乘以 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; //乘以2保留个位
else
return (a * 2 + 5) % 10; //乘以2加5保留各位
}
//计算进位
int jin_wei(char* p)
{
char* level[] =
{
"142857",
"285714",
"428571",
"571428",
"714285",
"857142"
}; //多位数超过n/7要进n
char buf[7];
buf[6] = '\0';
strncpy(buf,p,6); //将p字符串拷贝至buf中
int i;
for(i=5; i>=0; i--)
{
int r = strcmp(level[i], buf); //从后往前依次level中的串和buf比较
if(r<0) return i+1; //buf更大得出进位数i+1
while(r==0) //buf和level[i]相同了
{
p += 6; //往后偏移6位
strncpy(buf,p,6); //再拷贝6个字符到buf中
r = strcmp(level[i], buf); //再比较
if(r<0) return i+1; //如果buf大
if(r>0) return i; //如果level大
}
}
return 0;
}
//多位数乘以7
void f(char* s) //s代表多位数
{
int head = jin_wei(s); //head是s的进位
if(head > 0) printf("%d", head); //输出进位
char* p = s; //拷贝字符串指针
while(*p) //没有到末尾
{
int a = (*p-'0'); //依次字符转数字
int x = (ge_wei(a) + jin_wei(p+1)) % 10; //个位和后续字符串的进位两者相加取个位
printf("%d",x); //打印
p++; //指针后移
}
printf("\n");
}
int main()
{
f("428571428571");
f("34553834937543");
return 0;
}
🚩六角填数
⭐️问题描述
如图所示六角形中,填入1~12的数字。
使得每条直线上的数字之和都相同。
图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?
⭐️思路分析
使用全排列解决问题,可以用C++中自带的全排列函数,这样更为快速,也可以自己写一个全排列。
⭐️方法一:使用C++自带全排列函数
#include
#include
#include
using namespace std;
void check(vector data){
int r1 = 8+data[0]+data[1]+data[2];
int r2 = data[2]+data[3]+data[4]+3;
int r3 = 11+data[5]+data[6];
int r4 = 1+data[1]+data[3]+data[7];
int r5 = data[4]+data[5]+data[7]+data[8];
int r6 = 1+data[8]+data[6]+data[0];
if(r1==r2&&r2==r3&&r3==r4&&r4==r5&&r5==r6){
printf("%d %d %d %d %d %d %d %d %d\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]);
printf("*位是:%d",data[6]);
}
}
int main(){
vector data;
for(int i=4;i<8;i++){
data.push_back(i);
}
for(int i=9;i<13;i++){
data.push_back(i);
}
data.push_back(2);
do{
check(data);
}while(next_permutation(data.begin(),data.end()));
return 0;
}
⭐️方法二:自写全排列函数
#include
using namespace std;
int data[] = {2,4,5,6,7,9,10,11,12};
int ans = 0;
bool check(){
int r1 = 8+data[0]+data[1]+data[2];
int r2 = 8+data[8]+data[6]+3;
int r3 = 3+data[2]+data[3]+data[4];
int r4 = 1+data[0]+data[8]+data[7];
int r5 = 1+data[1]+data[3]+data[5];
int r6 = data[7]+data[6]+data[5]+data[4];
if(r1==r2&&r2==r3&&r3==r4&&r4==r5&&r5==r6)
return true;
return false;
}
void circulate(int n){
if(n==8){
if(check()){
ans = data[8];
return;
}
}
for(int i=n;i<9;i++){
{
int temp = data[i];
data[i] = data[n];
data[n] = temp;
}
circulate(n+1);
{
int temp = data[i];
data[i] = data[n];
data[n] = temp;
}
}
}
int main(){
circulate(0);
cout<
🚩蚂蚁感冒
⭐️问题描述
长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
⭐️解题思路
黑色代表首只感冒蚂蚁
红色代表会感冒蚂蚁
蓝色代表不会感冒蚂蚁
图 1 2 为一般情况 图 3 4 为特殊情况
(两只蚂蚁相遇各自反向可以看作是两只蚂蚁分别继续前进, 然后假如感冒蚂蚁向左行,则会感染它左边所有向右行的蚂蚁,因为它继续向左行, 别感染的第一只蚂蚁继续向右行,感染所有它右边向左行的蚂蚁。)
⭐️代码
#include
#include
using namespace std;
const int N = 100;
int a[N + 1];
int n;
int ans;
void solve() {
scanf("%d", &n);
int i = 0, t = 0, h = 0;
for (i = 0; i < n; i++) {
scanf("%d", &t);
if (i == 0) h = t; //记录第一只感冒的蚂蚁
a[abs(t)] = t;
}
//下面开始统计
if (h > 0) {
for (i = h + 1; i <= N; i++) {
if (a[i] < 0) ans++;
}
if (ans > 0) {
for (i = h - 1; i > 0; i--) {
if (a[i] > 0) ans++;
}
}
} else {
//注意h是负数
for (i = -h - 1; i > 0; i--) {
if (a[i] > 0) ans++;
}
if (ans > 0) {
for (i = -h + 1; i <= N; i++) {
if (a[i] < 0) ans++;
}
}
}
printf("%d\n", ans + 1); //最后加上第一只感冒的蚂蚁
}
int main(void) {
solve();
return 0;
}
#include
int abss(int s)//取绝对值
{ if(s<0)return -s;
else return s;
}
int main()
{
int qans=0,hans=0,n,i,gm,s;
scanf("%d",&n);
scanf("%d",&gm);//gm 首个感冒蚂蚁 位值
for(i=1;i0)qans++;//当在首个蚂蚁左侧并且正向 必感冒
}
if(gm>0&&hans!=0||gm<0&&qans!=0)printf("%d",qans+hans+1);
else printf("1");//当首个感冒蚂蚁方向为正时 在首个蚂蚁右侧并且反向 为 0 或
return 0; //当首个感冒蚂蚁方向为负时 在首个蚂蚁左侧并且反向 为 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
⭐️思路分析
由题目容易知道使用动态规划来解决,设定一个四维数组 dp[55][55][15][15],此数组用于存放当前的行动方案数量,由题目给出的数据范围可以推测出设定的数组不会使内存爆炸,dp[i][j][k][c]我们定义为到 (i,j) 这个点时,拿到了k件物品,并且当前的物品的最大价值小于c的方案数,那么可以推测出下面几种情况:
-
当mat[i][j] > 目前的最大价值(mat[i][j]表示位于(i,j)坐标的物品的价值)时,也就是说此时如果要取走(i,j)坐标的物品,那么位于(i-1,j)和(i,j-1)坐标的价值肯定小于mat[i][j],那么此时设置一个tmp1
tmp1 = dp[i-1][j][k-1][mat[i][j]] + dp[i][j-1][k-1][mat[i][j]] -
不管mat[i][j]大于当前的最大价值时,也可以选择不取位于(i,j)的物品,当mat[i][j]小于当前的最大价值时,则不能取走(i,j)的物品,所以不管是大于还是小于,都存在不取的这种情况,此时设置一个tmp2
tmp2 = dp[i-1][j][k][c] + dp[i][j-1][k][c]
最后 dp[i][j][k][c] = (tmp1%mod + tmp2%mod)%mod即可得出当前的方案数
最后输出dp[n][m][k][13]
⭐️代码
#include
#include
#include
using namespace std;
const int MOD = 1e9+7;
int mat[55][55];
int dp[55][55][15][15];
int n,m,k,ans;
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&mat[i][j]);
int tmp1,tmp2;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
for(int l=0;l<=k;++l)
for(int c=0;c<=13;++c)
{
tmp1 = 0;
if(i==1&&j==1) //此处表示初始条件
{
if(l==0) dp[i][j][l][c] = 1;
if(l==1&&c>mat[i][j]) dp[i][j][l][c]=1;
continue;
}
if(c>mat[i][j]&&l) tmp1 = dp[i-1][j][l-1][mat[i][j]] + dp[i][j-1][l-1][mat[i][j]];
tmp2 = dp[i-1][j][l][c] + dp[i][j-1][l][c];
dp[i][j][l][c] = (tmp1%MOD+tmp2%MOD)%MOD;
}
printf("%d\n",dp[n][m][k][13]);
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。
⭐️代码
#include
#include
using namespace std;
//a为原数组,b为按大小排序的数组,c为b的树状数组,d为暂存的不开心值 ,e为等差数列存储不高兴值的递增值
int a[100001],b[1000003],c[1000003],d[1000003];
long long int e[100002];
//位运算
int lowbit(int x)
{
return x&(-x);
}
//定义修改C数组的函数,第一个值代表数组位置,第二个代表数组值,在此题中只需默认加一
void update(int local,int num){
int n=local,add;
add=num-b[local];
b[local]=num;
while(n<1000002){
c[n]+=add;
n+=lowbit(n);
}
}
//查询前多少区间的和
int read(int i){
int n=i,sum=0;
while(n!=0){
sum+=c[n];
n-=lowbit(n);
}
return sum;
}
//清零函数
void ini(){
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
}
int main(){
int i,n;
long long int sum=0;
cin>>n;
ini();
for(i=0;i>a[i];//按顺序存储进来的小朋友身高
update(a[i]+1,b[a[i]+1]+1);//修改b和c数组,
d[i]=i-read(a[i])-b[a[i]+1]+1;//计算在第i个小朋友进来时,前面比他高的人数
}
ini();
for(i=n-1;i>=0;i--){
update(a[i]+1,b[a[i]+1]+1);//修改b和c数组,
d[i]+=read(a[i]);//计算在第i个小朋友进来时,后面比他矮的人数
}
e[1]=1;
for(i=2;i
🍊🍊🍊
总结不易,看到这那就来个三连吧,肝。。。🍺🍺🍺
🍊🍊🍊
署名:左手の明天
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)