Solve the Problem of ownCloud: ‘No Keychain Service Available’ on Ubuntu 18.04

Operating Environment

Operating system: Ubuntu 18.04.2 LTS
ownCloud client version: 2.4.1

Problem Description

I use ownCloud in Ubuntu and I add one account to it. But whenever I reboot Ubuntu, ownCloud will tell me: “No keychain service available” and I’ll be asked to enter the password once, as show in the figure 1:

Figure 1
Figure 1

Once I enter the password, ownCloud will work properly. But once I restart Ubuntu Linux, that happens again and again. Passwords should be stored, but it didn’t.

Solve the Problem

I found a solution on Github through Bing and that link is HERE. It seems that I am not the only one who has encountered this problem.

The solution is very simple, installing:

sudo apt install libgnome-keyring0

Then, reboot Ubuntu Linux, after you log in to the system, you will be asked to enter a password once, only once, whether you restart Ubuntu or not, you will not be asked to enter ownCloud’s password again unless you exit ownCloud account.

This problem has been solved.

在 Windows 10 上优化 CodeBlocks 外观 (主题 + 字体)

操作环境

操作系统: Windows 10 64 位 中文家庭版
CodeBlocks 版本: Code::Blocks 17.12

操作说明

CodeBlocks 是一款优秀的 IDE, 但是其默认的主题实在是不能满足我对一个代码编译器最基本的需求: 不使用亮色主题.
CodeBlocks 默认的主题是白色的, 如图 1:

图 1
图 1

在写代码时, 编辑器通常都是全屏显示的, 白色的主题看久了眼睛是受不了的. 不过, 好在 CodeBlocks 官网上提供了暗色的主题可供选择, 本文就介绍一下通过 CodeBlocks 官网提供的主题代码更换 CodeBlocks 主题以及修改 CodeBlocks 默认字体的方法.

继续阅读“在 Windows 10 上优化 CodeBlocks 外观 (主题 + 字体)”

在 Debian 7 Linux 中将 PHP 5.4 升级到 PHP 5.6

操作环境

root@IronMan:~# cat /etc/issue
Debian GNU/Linux 7 \n \l

操作步骤

指定软件源, 编辑:

vim /etc/apt/sources.list.d/dotdeb.list

写入如下内容:

deb http://packages.dotdeb.org wheezy-php56 all
deb-src http://packages.dotdeb.org wheezy-php56 all

将上述软件源加入 apt key:

wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -

更新可用包列表:

aptitude update

升级 PHP 版本:

aptitude install php5-cli php5-fpm

2017 年蓝桥杯 C 语言 B 组省赛第 2 题: 等差素数列

题目

标题:等差素数列

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

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

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

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

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

题目分析

首先, 素数 (质数) 都是大于 1 的, 因此 1 不是素数, 这点在题目中也有说明.
本题的解题思路是这样的:
我们首先需要定义一个用于判断一个数是不是素数的函数, 下面这个函数就可以判断一个大于 2 的数是不是一个素数, 如果是素数就返回真:

bool f(int x){
    for(int i=2;i<x;i++){
        if(x%i==0){
            return 0;
        }
    }
    return 1;
}

这里需要注意的是, 如果把上面这个判断素数的函数写成下面这样是不对的, 因为如果一个数能够整除除了自身和 1 之外的其他数则可以断定该数不是素数, 但是如果一个数不能够整除除了自身和 1 之外的其他数中的一个, 是不能判断其是不是素数的, 错误的素数判断程序如下:

bool f(int x){
    for(int i=2;i<x;i++){
        if(x%!=0){
            return 1;
        }
    }
    return 0;
}

之后, 我们需要从素数的起始位置, 也就是数字 2 开始, 从小到大依次判断前 1 个数加 1 是不是素数, 如果不是素数且之前计算出来的数字个数小于 10, 那么第 2 个素数开始进行上面的逐个加 1 的操作, 直到第 99999 个数字 (这个数字不一定是素数, 如果不是素数不参加之前的运算) 为止, 如果不能以 1 为公差找到 10 个数字, 则之后还是从数字 2 开始逐个加 2 并判断是不是素数, 如果不是素数则从第二个素数开始逐个进行加 2 的操作, 直到第 99999 个数字为止, 如果不能以 2 为公差找到 10 个数字, 则之后从数字 2 开始进行加 3 的操作…直到第 99999 个数字为止.

如果计算之后找不到结果可以将上面提到的有关搜索范围适当扩大.

在具体的编程实现上有以下两种.

程序 1:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int a[99999];
bool f(int x){
    for(int i=2;i<x;i++){
        if(x%i==0){
            return 0;
        }
    }
    return 1;
}

int main(){

    for(int a=2;a<99999;a++){ //遍历首项
        for(int b=1;b<999;b++){ //遍历公差

//使用十层 if 判断寻找符合条件的数值, 能抵达第十层的说明满足条件, 输出之
            if(f(a)){
                if(f(a+b*1)){
                    if(f(a+b*2)){
                        if(f(a+b*3)){
                            if(f(a+b*4)){
                                if(f(a+b*5)){
                                    if(f(a+b*6)){
                                        if(f(a+b*7)){
                                            if(f(a+b*8)){
                                                if(f(a+b*9)){
                                                    cout<<b<<endl;
                                                }else{
                                                    continue;
                                                }
                                            }else{
                                                continue;
                                            }
                                        }else{
                                            continue;
                                        }
                                    }else{
                                        continue;
                                    }
                                }else{
                                    continue;
                                }
                            }else{
                                continue;
                            }
                        }else{
                            continue;
                        }
                    }else{
                        continue;
                    }
                }else{
                    continue;
                }
            }else{
                continue;
            }
        }
    }

    return 0;
}

程序 2:

#include<iostream>
#include<bits/stdc++.h>
#define MAX 999999
using namespace std;
int a[MAX];

bool f(int x){ //判断一个数字是不是素数的函数
    for(int i=2;i<x;i++){
        if(x%i==0){
            return 0;
            //如果能整除, 则表示这是一个非素数, 返回假 (0)
        }
    }
    return 1;
    //如果不能整除, 则表示这是一个素数, 返回真 (0)
}

int main(){

//遍历从 2 到 99999 之间的数字, 将其中的素数标记为 1
    for(int i=2;i<99999;i++){
        if(f(i)){
            a[i]=1;
        }
    }

    for(int delta=1;delta<999;delta++){
    //遍历从 1 到 999 之间的公差
        for(int i=2;i<99999;i++){
        //遍历数组 a[i]

            int step;
            for(step=0;step<10;step++){
            //限制只遍历数组 a[i] 中的 10 个数字

                //如果第 i+delta*step 个数字不是素数就退出
                if(a[i+delta*step]!=1){
                    break;
                }
            }

            //如果能完整的走完 10 步则表示找到了答案
            if(step==10){
                cout<<delta<<endl;
                return 0;
            }
        }
    }
    return 0;
}

本题的正确答案:
210

2016 年蓝桥杯 C 语言 B 组省赛第 3 题: 凑算式 (两种方法)

题目

凑算式

     B      DEF
A + --- + ------- = 10
​     C      GHI


(如果显示有问题,可以参见【图1.jpg】)


这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。

比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

图 1
图 1

题目分析

本题就是一个无重复全排列的问题, 在 C++ 中实现无重复全排列有以下两种主要方式:

  1. 通过 next_permutation() 函数实现全排列

next_permutation() 全排列函数只能对有序数列的数组进行全排列, 示例如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[3]={0,1,2};
    while(next_permutation(a,a+3)){
        cout<<a[0]<<a[1]<<a[2];
        cout<<endl;
    }
    return 0;
}
  1. 通过循环实现全排列

假设我们要对从 1 到 3 这个三个数字进行全排列, 那么我们可以使用如下的方式进行:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    for(int a=1;a<=3;a++){
        for(int b=1;b<=3;b++){
            if(b!=a){
                for(int c=1;c<=3;c++){
                    if(c!=a&&c!=b){
                    cout<<a<<" "<<b<<" "<<c<<endl;
                    }
                }
            }
        }
    }
    return 0;
}

另外, 在本题中需要注意的是, 本题给出的算式是存在除法的, 涉及除法就不得不考虑精度的问题. 为了解决精度的问题, 一方面我们可以使用将整型强制转换成 double 型的方式, 另一方面也可以使用将除法转换成乘法的方式进行计算.

根据上面的分析, 我们可以有两种方法计算本题.

方法一: 使用 C++ 中的 next_permutation() 函数计算, 程序如下:

#include<iostream>
#include<bits/stdc++.h> //万能头文件, 包含所有函数
using namespace std;
int main(){
    int a[9]={1,2,3,4,5,6,7,8,9};
    int sum=0;
    while(next_permutation(a,a+9)){
    //对数组a的前9个元素进行全排列, 也就是对全部元素进行全排列

        double sum2=(double)a[0]+(double)a[1]/a[2]+double(a[3]*100+a[4]*10+a[5])/(a[6]*100+a[7]*10+a[8]);
        if(sum2==10.0){
            sum++;
        }
    }
    cout<<sum<<endl;;
    return 0;
}

方法二: 使用九层 for 循环计算, 程序如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    int ans=0;
    for(int a=1;a<=9;a++){
        for(int b=1;b<=9;b++){
            if(b!=a){
                for(int c=1;c<=9;c++){
                    if(c!=a&&c!=b){
                        for(int d=1;d<=9;d++){
                            if(d!=a&&d!=b&&d!=c){
                                for(int e=1;e<=9;e++){
                                    if(e!=a&&e!=b&&e!=c&&e!=d){
                                        for(int f=1;f<=9;f++){
                                            if(f!=a&&f!=b&&f!=c&&f!=d&&f!=e){
                                                for(int g=1;g<=9;g++){
                                                    if(g!=a&&g!=b&&g!=c&&g!=d&&g!=e&&g!=f){
                                                        for(int h=1;h<=9;h++){
                                                            if(h!=a&&h!=b&&h!=c&&h!=d&&h!=e&&h!=f&&h!=g){
                                                                for(int i=1;i<=9;i++){
                                                                    if(i!=a&&i!=b&&i!=c&&i!=d&&i!=e&&i!=f&&i!=g&&i!=h){
                                                                        double sum2=(double)a+(double)b/c+double(d*100+e*10+f)/(g*100+h*10+i);
                                                                        if(sum2==10.0){
                                                                            ans++;
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

2016 年蓝桥杯 C 语言 B 组省赛第 2 题: 生日蜡烛 (三种解法)

一、题目

生日蜡烛

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

现在算起来,他一共吹熄了236根蜡烛。

请问,他从多少岁开始过生日party的?

请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

二、题目分析

这道题可以使用循环来解决. 根据实际情况, 首先假设”某君”的年龄没有超过100岁, 之后假设他从 0 岁开始过生日并吹蜡烛, 之后一直累加, 直到他吹蜡烛的总数为 236, 如果从 0 岁开始计算没有出现吹了 236 根蜡烛的情况, 那么就从 1 岁开始计算, 直到计算出吹了 236 根蜡烛的情况.

在具体的程序实现方式上有三种不同的解法.

第一种解法是, 第一层 for 循环用来遍历开始过生日的年龄, 第二层 for 循环用来遍历现在的年龄, 第三层 for 循环用来遍历从开始年龄到现在年龄之间吹的蜡烛的总数, 程序如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    for(int start=1;start<100;start++){
    //遍历开始过生日的年龄

        for(int now=1;now<100;now++){
        //遍历现在的年龄

            int sum=0;
            if(start<=now){
            //现在的年龄需要大于过去的年龄

                for(int i=start;i<=now;i++){
                //累加计算蜡烛总数
                    sum=sum+i;//注意这里要累加的变量是 i 不是 start
                }
                if(sum==236){
                //如果蜡烛总数为 236 则输出结果
                cout<<"开始的时间:"<<endl;
                cout<<start<<endl;
                cout<<"现在的时间:"<<endl;
                cout<<now<<endl;
                }
            }
        }
    }
    return 0;
}

第二种解法是, 第一层 for 循环用来遍历开始过生日的年龄, 第二层 for 循环用来遍历下一次过生日时的年龄并进行累加, 程序如下:

#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
    for(int i=0;i<200;i++){ //i 为开始年龄
        int sum=0;
        //sum 要调用它的循环外最近的地方定义并初始化

        for(int j=i;j<200;j++){
        //j 为下次过生日时的年龄

            sum=sum+j;
            //计算吹蜡烛的总数

            if(sum==236){
                cout<<"开始的年龄是:"<<i<<endl;
                cout<<"现在的年龄是:"<<j<<endl;
            }
        }
    }
    return 0;
}

第三种解法是, 利用等差数列的求和公式进行计算.

等差数列的前 n 项和:

$S_n$ $=$ $\frac{n(a_1+a_n)}{2}$

等差数列的第 $n$ 项值:

$a_n$ $=$ $a_1$ $+$ $(n-1)$ $d$

等比数列的前 $n$ 项和:

$S_n$ $=$ $\frac{a_1(1-q^n)}{1-q}$

等比数列的第 n 项值:

$a_n$ $=$ $a_1$ $q^{(n-1)} $

根据等差数列的数学原理, 我们可以编写出如下计算程序:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    for(int i=1;i<=100;i++){
    //i 为数列的首项

        double sum=0;
        int a=0;
        int b=0;
        for(int j=1;j<=100;j++){
        //j 为数列递增的次数

            b=j+1;
            //目前数列有 b 项 (项数比递增的次数多 1)

            a=i+b-1;
            //计算本数列最后一项的值

            sum=b*(i+a)/2;
            //计算本数列的和

            /*每计算出一次 sum 的值都要立即进行一次判断
            判断语句不能放在本次循环的外面
            因为一个循环会遍历所有的数值之后才退出
            如果把判断语句放在循环的外面
            则不能使每次循环得出的数值都被判断*/
            if(sum==236){
            cout<<"开始过生日的年龄为:"<<i<<endl;
        }
        }

    }
    return 0;
}

在使用循环遍历的时候, 如果不能计算出我们想要的结果, 这个时候可以把循环的次数改小一些, 之后进行单步调试, 看看是不是和我们手算出来的结果一致.

2016 年蓝桥杯 C 语言 B 组省赛第 1 题: 煤球数目

题目

煤球数目

有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
….
如果一共有100层,共有多少个煤球?

请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目分析

本题是一个找规律的问题, 找到的规律如下:

第1层: 0+1=1
第2层: 1+2=3
第3层: 3+3=6
第4层: 6+4=10
……

可以看到, 规律就是上一层的煤球个数加上本层的层数就可以得到本层的煤球个数.

之后用编程实现, 代码如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int sum=0;
    int sum2=0;
    for(int i=1;i<=100;i++){
        sum=sum+i;
        sum2=sum2+sum;
    }
    cout<<sum2<<endl;
    return 0;
}

本题正确答案:
171700

2014 年蓝桥杯 C 语言 B 组省赛第 3 题: 李白打酒

题目

标题:李白打酒

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。

题目分析

关于方案数量的问题往往都是使用深搜. 使用递归实现深搜可以使我们不必关心遍历的具体过程, 只需要把题目中给出的条件转换成程序语言即可.
根据题目信息, 变量有”店”, “酒”和”花”, 因此我们的递归函数必须包含这三个变量, 即:

void f(int dian, int hua, int jiu)...

根据”逢店加一倍,遇花喝一斗。”可以得出如下两个对函数 f() 自身进行调用的语句:

if(遇到店){
  f(dian-1,hua,jiu*2);
}

if(遇到花){
  f(dian,hua-1,jiu-1);
}

递归的边界是遇到了 5 次店, 10 次花, 并且最后酒喝光了, 即:

dian==0&&hua==0&&jiu==0

但是上面的分析过程 (对递归边界的定义) 是存在错误的. 我们根据上面的分析过程可以写出下面这个 (错误的) 程序:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int ans=0;

void f(int dian, int hua, int jiu){
        if(dian>0&&jiu>=0){
            f(dian-1,hua,jiu*2);
        }

        if(hua>0&&jiu>=1){
            f(dian,hua-1,jiu-1);
        }

        if(dian==0&&hua==0&&jiu==0){
            ans++;
        }

    }

int main(){

    f(5,10,2);
    cout<<ans<<endl;

    return 0;
}

上面这个程序的运行结果是:
27

“27”看上去也”像是”一个正确答案. 但是, 如果我们仔细分析题目就会发现, 上面这个程序没有满足题目中给出的下面这个条件:

已知最后一次遇到的是花,他正好把酒喝光了

也就是说, 李白最后一次遇到的是花, 而且在刚遇到的花的时候, 他的酒壶里还剩 1 斗酒, 随后”遇花喝一斗”把酒壶里面的酒都喝光了. 至此, 李白一共遇到了 5 次店, 10 次花, 并且喝完了全部的酒.

但是, 在上面的程序中, 计算的仅仅是李白”遇到了 5 次店, 10 次花, 并且喝完了全部的酒”, 存在李白最后连续遇到了两次花, 每次喝一斗, 最后把酒喝完的情况, 也存在李白最后连续遇到了四次花, 每次喝一斗, 最后把酒喝完的情况(题目中没有提到酒壶容量的上限).

为了满足这个”已知最后一次遇到的是花,他正好把酒喝光了”的条件, 我们先把最后一次遇到花并喝一斗酒的情况减去, 这样只需要计算李白遇到 5 次店, 9 次花, 并剩下了 1 斗酒有多少种情况就可以了, 正确的程序如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int ans=0; //定义全局变量用于计数

void f(int dian, int hua, int jiu){

/*模拟李白遇到店的情况
若要遇到店, 则剩下的店的数量必须大于 0
遇到店的时候, 剩下的花的数量不变但必须不为负数
遇到店之前不能把酒壶里面的酒喝成负数*/
        if(dian>0&&jiu>=0&&hua>=0){
            f(dian-1,hua,jiu*2);
        }

/*模拟李白遇到花的情况
若要遇到花, 则剩下的花的数量必须大于 0
遇到花的时候, 剩下的店的数量不变但必须不为负数
遇到花之前酒壶里面的酒至少要剩 1 斗以便于遇到花时喝*/        
        if(hua>0&&jiu>=1&&dian>=0){
            f(dian,hua-1,jiu-1);
        }

        if(dian==0&&hua==0&&jiu==1){
            ans++;
        }

    }

int main(){
    f(5,9,2);
    cout<<ans<<endl;
    system("pause");
    return 0;
}

本题正确答案:
14

2014 年蓝桥杯 C 语言 B 组省赛第 2 题: 切面条

题目

标题:切面条

一根高筋拉面,中间切一刀,可以得到2根面条。

如果先对折1次,中间切一刀,可以得到3根面条。

如果连续对折2次,中间切一刀,可以得到5根面条。

那么,连续对折10次,中间切一刀,会得到多少面条呢?

答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。

题目分析

本题其实可以不需要使用编程的方式解决, 这是一个数列找规律的问题. 对于找规律的问题需要记住的一点就是要手算出尽可能多的项, 这样找出来的规律才比较可靠 (题目中已经给出了数列的前三个值, 如果最终的规律可以靠前三个数列导出的话, 那么这道题就没什么考点了, 因此至少需要计算出数列中第 4 个数的值).

数列的规律可以从以下几个方面寻找:

  • 两个数值间的关系是否和两个数之间的差值有关系, 差值的变化是否具有某种规律, 例如呈指数增长的差值;
  • 前两个数的和 (或者差, 积, 商) 是否可以得出其后的数.

通过使用 Windows 系统中的”画图”工具绘制出前 4 种情况(如果时间充裕的话可以在得出结果后绘制第 5 种情况以验证对规律的猜测是否正确), 如图 1

图 1
图 1

由此, 我们可以得到关于面条个数的这样一个数列:

2, 3, 5, 9

接着我们可以得到这样一个规律:

2+0=2 (对折 0 次)
2+1=3 (对折 1 次)
3+2=5 (对折 2 次)
5+4=9 (对折 3 次)

进而得到:

2+2^0=3 (对折 1 次)
3+2^1=5 (对折 2 次)
5+2^2=9 (对折 3 次)

规律找到这里, 我们可以使用程序进行之后的计算, 程序如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    int a=2;
    int ans=2;

    for(int i=0;i<=9;i++){
            ans=ans+pow(a,i);
    }
    cout<<ans<<endl;
    return 0;
}

程序运行结果:

1025

如果不知道 C/C++ 用于求次方的函数是什么, 也可以使用循环代替, 下面的程序同样可以计算出最终结果:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int main(){
    int ans=5;

    for(int i=2;i<=9;i++){
        int b=2;
        int a=2;
        for(int j=1;j<i;j++){
            b=b*a; //a 在循环的过程中必须始终为 2
        }
            ans=ans+b;
    }
    cout<<ans<<endl;
    return 0;
}

程序运行结果:

1025

在运行程序之前可以先设置断点进行单步调试, 看看程序运行的前几步是不是和我们手动计算出来的结果 (和规律) 一致.

另外, 正如本文开头所说的, 本题可以不通过编程的方式解决, 因为这可以看做是一个数学问题, 就是找数列的规律. 但是为什么我们上面找到数列的规律后还需要用程序计算呢? 因为上面得到的规律中, 等号左边的变量有两个, 每一步的计算都需要上一步的结果作为支撑 (当然, 也可以不编程, 直接借助系统中的计算器逐步计算, 这个方法也可以用于对程序计算结果的验证), 每一步的计算都不是独立的, 这样的规律显然不适合手算, 之前找到的规律如下:

2+2^0=3 (对折 1 次)
3+2^1=5 (对折 2 次)
5+2^2=9 (对折 3 次)

为了方便手算, 我们必须想办法去掉一个变量, 于是, 就有了下面这个规律:

1+2^0+2^0=3 (对折 1 次)
1+2^1+2^1=5 (对折 2 次)
1+2^2+2^2=9 (对折 3 次)

进而得到:

1+2*2^0=3 (对折 1 次)
1+2*2^1=5 (对折 2 次)
1+2*2^2=9 (对折 3 次)

进而又可得到:

1+2^1=3 (对折 1 次)
1+2^2=5 (对折 2 次)
1+2^3=9 (对折 3 次)

在上面的规律中, 对每次对折的求解都不依赖上一次对折得出的相关数值, 变量只有一个, 即对折的次数, 因此可以通过一次计算就得出对折 10 次后再在中间切一刀能够得到的面条个数, 计算过程与结果为:

1+2^10=1025

本题需要注意的一点是, 得到两根面条的时候 (第 1 次切的时候) 对折的次数是 0 次.
本题的关键是正确地找出数列中的多个数值, 如果只找出前三个数值则本题很可能会得出错误的结果.

2014 年蓝桥杯 C 语言 B 组省赛第 1 题: 啤酒和饮料

题目

标题:啤酒和饮料

啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。

我们还知道他买的啤酒比饮料的数量少,请你计算他买了几罐啤酒。

注意:答案是一个整数。请通过浏览器提交答案。

不要书写任何多余的内容(例如:写了饮料的数量,添加说明文字等)。

题目分析

这里使用使用循环暴力破解即可, 根据啤酒和饮料的价格以及一共花费了八十多块钱可以大致估计, 啤酒的数量不会超过 50 罐, 饮料的价格不会超过 60 罐, 由于有啤酒和饮料两个, 因此用两个嵌套的 for 循环对其进行遍历即可.

下面先来看一个有问题的程序.

下面这个程序在逻辑上是符合的, 但是无法运行出结果:

#include <iostream>
using namespace std;
int main(){
    for (int i=1; i<=50; i++){
        for (int j=1; j<=60; j++){
            if((i<j)&&(i*2.3+j*1.9==82.3)){
                cout<<i<<" "<<j<<endl;
            }
        }
    }
    return 0;
}

无法出结果的原因是, 如果参与运算的有浮点数, 那个其运算结果是不能用于比较是否相等的 (“==”两边不能是浮点数), 因为浮点数的精度不同可能导致两个本来相同的浮点数不相等.

正确的比较方法是计算两个数的差值, 如果差值小于一个极小的数就表明这两个数字是相等的, 正确的程序如下:

#include<iostream>
#include<cmath>
using namespace std;
int main(){
    for (int i=1; i<=50; i++){
        for (int j=1; j<=60; j++){
            if((i<j)&&abs((i*2.3+j*1.9) - 82.3)<0.0000000000001){
                //abs()库函数用于求绝对值
                cout<<i<<" "<<j<<endl;
            }
        }
    }
    return 0;
}

运行结果:

11 30

当然, 本题也可以通过将题目中给出的数据都扩大 10 倍, 将浮点类型转换成 int 类型之后再计算, 程序如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    for(int pj=1;pj<60;pj++){
        for(int yl=1;yl<60;yl++){
            if(pj<yl&&pj*23+yl*19==823){
                cout<<"啤酒:"<<pj<<endl;
                cout<<"饮料:"<<yl<<endl;
            }
        }
    }
    return 0;
}

运行结果:

啤酒:11
饮料:30

其中 11 是啤酒的罐数且满足啤酒的罐数小于饮料的罐数 (可以在得出结果后使用 PC 中的计算器验证一下).
本题正确答案:
11

2013 年蓝桥杯 C 语言 B 组省赛第 3 题: 第39级台阶

题目

题目标题: 第39级台阶

小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

站在台阶前,他突然又想着一个问题:

如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

请你利用计算机的优势,帮助小明寻找答案。

要求提交的是一个整数。
注意:不要提交解答过程,或其它的辅助说明文字。

题目分析

本题的正确答案是:

51167078

这里涉及递归, 斐波那契数列和动态规划, 可以使用深度优先搜索 (DFS) 的思想解决问题.

首先说一下深度优先搜索. 深搜的原则就是对每一个可能的路径都深入访问直到不能继续深入访问为止, 而且每个节点只访问一次. 深搜的应用条件是上一步的走法和下一步的走法的规则是一样的且该问题具备边界以结束深搜.

首先可以简化一下这个问题, 去掉题目中要求的”走偶数步”的限制. 之后, 剩下的问题就是每次上一个或者两个台阶, 一共有多少种走法, 第一步有两种可能(走一个台阶或者走两个台阶), 随后的每走过一步的下一步也都是有两种走法(走一个台阶或者走两个台阶).

假设函数 f(n) 可以计算在上面的条件下走完 n 阶台阶会有多少种走法, 则:

走完 1 个台阶之后 (走了 1 步), 剩余的走法有 f(n-1) 种;

走完 2 个台阶之后 (走了 1 步), 剩余的走法有 f(n-2) 种.

结束条件有两个, 一个是恰好走完了 39 个台阶, 另一个是走到了第 40 个台阶(正着走的情况下, 只剩下一个台阶时却迈了两步)或者走到了第 -1 个台阶(倒着走的情况下, 只剩下一个台阶的时候却迈了两步).

正着走: 可以认为是从楼梯下面往上面走;
倒着走: 可以认为是从楼梯上面往下面走;
正着走和倒着走的效果是一样的 (例如当”楼梯”是水平的”斑马线”的时候).

使用递归实现深搜的函数大致形式如下:

递归函数f(...){
    if(...){ //本层递归函数结束条件 1
        /* code */
    }else if (...) { //本层递归函数结束条件 2
        /* code */
    }else{
        递归函数f(...)//可能的步骤 1
        递归函数f(...)//可能的步骤 2
    }
}

在具体使用递归解决深搜问题的时候, 不同的思路和方法的最终实现方式会有些差别, 具体情况可以参考如下 4 个程序 (每个程序都可以独立解决”第39级台阶”这个问题).

程序 1 如下:

#include<iostream>
#include<stdio.h>
using namespace std;
int ans; //用于保存所有可能的走法
void f(int n, int step){//n: 剩下的阶梯数, step: 已走的步数

/*剩下的台阶数是负数 (如果最后只剩下一个台阶却走了两步
会导致产生剩下负数个台阶的情况), 这是不可能发生的,
因此退出 f() 函数.*/
    if(n<0){//判断边界条件, 函数出口 1

        return;
/*在 void 函数中使用"return"可以出发函数的强制结束,
类似于循环结构中的 "break", 在这里"return"用于退出
本层深度遍历, 回到上一个未被遍历的节点继续之后的深度遍历.
*/

    }
    if(n==0&&step%2==0){//判断边界条件, 函数出口 2
        ans++;
        return;
    }

/*尝试每一种可能的结果("n-1"和"n-2")并触发
下一步的递归操作 ("n-1,step+1"和"n-2,step+1")
*/
    f(n-1,step+1); //下一步可能的走法 1
    f(n-2,step+1); //下一步可能的走法 2
}
int main(){
    f(39,0);
    cout << ans << endl;
    return 0;
}

上面的程序是倒着计算(倒着走楼梯)的, 也可以按照正着计算(正着走楼梯)的方法写程序, 程序 2 如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int sum=0;

void f(int n, int step){

        if(n==39&&step%2==0){
            sum++;
            return;
        }

        if(n>39){
            return;
        }

        f(n+1,step+1);
        f(n+2,step+1);

    }

int main(){
    f(0,0);
    cout<<sum<<endl;
    return 0;
}

为了使逻辑上更清晰一些, 可以对上面的程序 2 做以下修改, 修改后得到的程序 3 如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int sum=0;

void f(int n, int step){

        if(n==39&&step%2==0){
            sum++;
            return;
        }else if(n>39){
            return;
        }else{
            f(n+1,step+1);
            f(n+2,step+1);
        }

    }

int main(){
    f(0,0);
    cout<<sum<<endl;
    return 0;
}

当然, 递归函数除了可以使用没有返回值的 “void f()” 来定义, 也可以使用有返回值的”int f()”来定义, 例如程序 4:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

int sum=0;

int f(int n, int step){

        if(n==39&&step%2==0){
            sum++;
            return sum;
        }else if(n>39){
            return -1;
        }else{
            f(n+1,step+1);
            f(n+2,step+1);
            return 0;
        }

    }

int main(){
    f(0,0);
    cout<<sum<<endl;
    return 0;
}

2013 年蓝桥杯 C 语言 B 组省赛第 2 题 马虎的算式

题目

标题: 马虎的算式

小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。

有一次,老师出的题目是:36 x 495 = ?

他却给抄成了:396 x 45 = ?

但结果却很戏剧性,他的答案竟然是对的!!

因为 36 * 495 = 396 * 45 = 17820

类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54

假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)

能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?

请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。

答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。

题目分析

预备知识:
乘法交换律: a * b = b * a

该题目可以整理成以下几点:

  • 将三位数中间的数字拿出来放到两位数的中间, 更换前后两数的乘积相等.
  • 因为有 5 个不同的数字, 每个数字都可能取 1 到 9 不同的数字(不包括 0), 因此使用 5 层 for 循环, 将每个数字都从 1 尝试到 9, 看看是否满足 “ab * cde = adb * ce” 这样的形式.

使用编程解决问题的主要思路就是让程序一步步的满足所有题目给出的条件, 然后就可以通过一片片的循环得到最终的结果.

要满足的条件和对应的编程实现如下:

  • 需要有 5 个数字, 每个数字都是从 1 到 9 -> 5 个 for 循环
  • 5 个数字要各不相同 : if 判断, 每多出一个数字(每增加一层循环)都要判断这个数字是否与已有的数字相同, 只有与已有的数字不相同才继续向下循环.

解题程序如下:

#include<iostream>
#include<stdio.h> //不加这个不能使用 printf()函数
using namespace std;

int main(){
    int ans = 0;
    for (int a=1; a<10; a++){
        for (int b=1; b<10; b++){
            if(b!=a){
                for (int c=1; c<10; c++){
                    if(c!=a&&c!=b){
                        for(int d=1; d<10; d++){
                            if(d!=a&&d!=b&&d!=c){
                                for(int e=1; e<10; e++){
                                    if(e!=a&&e!=b&&e!=c&&e!=d){
                                        //判断是否满足 ab * cde = adb * ce
                                        if((a*10+b)*(c*100+d*10+e)==(a*100+d*10+b)*(c*10+e)){
                                            //为了验证结果是否正确, 可以将所有可能的结果都打印出来, 随机抽取几个手动验算
                                            printf("((%d*10+%d)*(%d*100+%d*10+%d)==(%d*100+%d*10+%d)*(%d*10+%d))=%d\n",a,b,c,d,e,a,d,b,c,e,(a*100+d*10+b)*(c*10+e));
                                            ans++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

正确答案是:

142

2013 年蓝桥杯 C 语言 B 组省赛第 1 题 高斯日记

题目

题目标题: 高斯日记

大数学家高斯有个好习惯:无论如何都要记日记。

他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210

后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?

高斯出生于:1777年4月30日。

在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。

高斯获得博士学位的那天日记上标着:8113

请你算出高斯获得博士学位的年月日。

提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21

请严格按照格式,通过浏览器提交答案。
注意:只提交这个日期,不要写其它附加内容,比如:说明性的文字。

题目分析

这一题是一个结果填空题,可以使用 Excel 解出答案。需要注意的有一下几点:

  • 充分利用和验证题目的示例,确定高斯出生的那一天是按第一天而不是第 0 天计算的。
  • 注意答案的提交格式,不要写成“1980-3-21”,而是:“1980-03-21”。
  • 注意闰年和非闰年的区别。能被 4 整除, 但不能被 100 整除的是闰年, 或者能被 400 整除的也是闰年. 闰年有 366 天,非闰年有 365 天. 闰年的 2 月有 29 天, 非闰年的 2 月有 28 天. 每 4 年中会有一个闰年.

首先, 借助 Excel 来计算出答案.

写下高斯的生日, 右键将单元格格式设置成”日期”:

图 1
图 1

根据年份和月份的规律可以计算出这样一个表格:

图 2

根据如下图所示的验证结果可以看到, 高斯出生的那天是按照第一天计算的, 同时这也验证了我们的计算方式是正确的:

图 3

当我们选中到 1978 年的时候,求和结果显示有 7916 天:

图 4
图 4

8113 – 7916 = 197

之后的 1799 年是非闰年, 其 2 月有28天, 计算如下:
31(1月) + 28(2月) + 31(3月) + 30(4月) + 31(5月) + 30(6月) = 181
197 – 181 = 16

因此可以知道, 高斯获取博士学位那一年是 1799 年 07 月 16 日
填写的答案就是:
1799-07-16

另外, 本题也可以使用编程解决, 程序如下:

//模仿翻日历的方式计算高斯获得博士学位的日期
#include<iostream>
using namespace std;

//判断是否是闰年的布尔函数
bool isLeapYear(int y){
        return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
    }

int main(int argc, const char *argv[]){
    int y = 1777;
    int m = 4;
    int d = 30;

    for (int i = 0; i < 8112; i++){
        d++;

        //如果出现 12 月 32 日 则代表下一年
        if (m == 12 && d == 32){
            y++;
            m = 1;
            d = 1;
            continue;
        }       
        //对除了 12 月之外的其他有 31 天的月份进行判断
        if ((m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10) && d == 32){
            m++;
            d = 1;
            continue;
        }

        //对除了 12 月之外的其他有 30 天的月份进行判断    
        if ((m == 4 || m == 6 || m == 9 || m == 11) && d == 31){
            m++;
            d = 1;
            continue;
        }       

        //判断闰年的 2 月
        if (m==2 && isLeapYear(y) && d == 30){
        //闰年的二月有 29 天, 因此如果出现第 30 天就需要进入下一月.
            m ++;
            d = 1;
            continue;
        }       

        //判断非闰年的 2 月
        if (m == 2 && !isLeapYear(y) && d == 29){
        //非闰年的二月有 28 天, 因此如果出现第 29 天就需要进入下一月.  
            m++;
            d = 1;
            continue;
        }
    }
    cout << y << " " << m << " " << d << endl;
    return 0;
}

运行结果:

图 5
图 5

需要注意的是, 填写答案时要按照要求的格式填写:
1799-07-16

CentOS/Ubuntu 创建 SWAP 交换分区

之前我写过一篇创建 Linux 交换分区的文章:
在不重装系统的情况下创建Linux的Swap分区
但是这次创建交换分区的方法和上次的有些区别, 再次记录一下.

操作环境

本文方案在以下操作系统中测试通过:
CentOS 7
Ubuntu 16.04

操作步骤

查看系统中的分区:

fdisk -l

或者, 查看当前分区:

df ./

根据上面查找到的分区信息, 选定一块分区, 从中划分出一个交换分区, 例如, 我选定的是 /dev/vda1 分区.

/dev/vda1 分区中分出一块大小为 4GB (4194304 字节) 的空间, 输出为 /var/swap, 命令如下:

dd if=/dev/vda1 of=/var/swap bs=1024 count=4194304

/var/swap 设置为交换分区:

mkswap /var/swap

设置开机自动挂载, 编辑:

vim /etc/fstab

添加如下信息:

/var/swap swap swap defaults 0 0

最后重启服务器:

reboot

重启后登录服务器就可以看到一个大小为 4GB 的交换分区了, 如图:

图 1
图 1

2017 年蓝桥杯 C 语言 B 组省赛第 1 题: 购物单

题目

标题: 购物单

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

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

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

题目分析

首先 ,这道题可以直接使用系统中的计算器逐个手算, 然后取一个大于且最接近整百的数值即可.
另外一种方法是使用 Word + Excel 辅助计算, 过程如下:

  1. 复制购物单的内容到 Word, 并使用替换功能去掉 *** 和”折”这些无关内容 (替换为空内容), 需要特别注意的是, 购物单中的”9折”, “8折”, 如果去掉”折”之后会变成”9″和”8″, 不符合实际意义, 应改成”90″和”80″;
  2. 把”半价”替换为”50″;
  3. 全选经过上面步骤处理后得到的文本, 依次打开”插入 / 表格 / 文本转换成表格”, 注意将”文字分隔位置”设置成”空格”, 这样生成的表格中, 上面文本中的单价和折扣额度会位于两列而不是一列, 如图 1:
图 1
图 1
  1. 删除生成的表格中空白的行和列;
  2. 新建一个 Excel 文件, 全选并复制 Word 文档中的表格, 之后粘贴到新建的 Excel 中;
  3. 在 Excel 的公式栏输入如下公式:
=A1*B1/100

之后拖动十字下拉柄将余下的列都进行上述计算;

  1. 输入如下公式求和:
=SUM(C1:C50)

计算结果如下:

5136.8595

因此应该填入的答案是:

5200

荒原之梦网全部内容均为原创,提供了涵盖考研数学基础知识、考研数学练习题、考研数学真题等方面,大量精心研发的学习资源。

豫ICP备17023611号-1 | 公网安备 - 荒原之梦 豫公网安备41142502000132号
Copyright©2017-2026 ZhaoKaifeng.com 版权所有 All Rights Reserved.

豫ICP备17023611号-1
  豫公网安备41142502000132号
Copyright©2026   ZhaoKaifeng.com   All Rights Reserved.

荒原之梦 自豪地采用WordPress