【2016蓝桥杯省赛】试题C++ B组试题

一、    煤球数目

作答:171700

#include <iostream>
using namespace std;

int main() {
        int sum=0,x=0;
        for(int i=1;i<=100;i++){
                 x+=i;
                 sum += x;
        }
        cout<<sum;                                  
}
View Code

二、    生日蜡烛

作答:26

#include <iostream>
using namespace std;

int main() {
    for(int i=0;i<236;i++){
        int sum=0;
        for(int j=i;sum<236;j++){
            sum+=j;
        }
        if(sum==236){
            cout<<i;
            break;
        }
    }
}
View Code

三、    凑算式

纯暴力+剪枝,剪成这样大概30s就跑出来了,觉得剪得差不多了,跑起来试试,反正跑的时候又不耽误继续写。

作答:29

#include <iostream>
#include <math.h>
using namespace std;

int gcd(int x, int y) {
    if (y == 0)return x;
    return gcd(y, x%y);
}
int lcm(int x, int y) {
    return x * y / gcd(x, y);
}
void simp(int &x, int &y) {
    int t = gcd(x, y);
    x /= t;
    y /= t;
}
void add(int &x1, int &y1, int x2, int y2) {
    int t = lcm(y1, y2);
    x1 = x1 * t / y1 + x2 * t / y2;
    y1 = t;
    simp(x1, y1);
}
int repeat(int A, int B, int C, int DEF, int GHI) {
    int a[10] = { 0 };
    a[A]++; a[B]++; a[C]++;
    while (DEF > 0) {
        a[DEF % 10]++;
        a[GHI % 10]++;
        GHI /= 10;
        DEF /= 10;
    }
    if (a[0] > 0)return 1;
    for (int i = 0; i < 10; i++) {
        if (a[i] > 1)return 1;
    }
    return 0;
}
int main() {
    int count = 0;
    for (int A = 1; A <= 9; A++) {
        for (int B = 1; B <= 9; B++) {
            if (A == B)continue;
            for (int C = 1; C <= 9; C++) {
                if (A == C || B == C || (A + B / (float)C > 10))continue;
                for (int DEF = 123; DEF <= 987; DEF++) {
                    for (int GHI = 123; GHI <= 987; GHI++) {
                        if (repeat(A, B, C, DEF, GHI)) continue;
                        else {
                            int a = A, b = B, c = C, def = DEF, ghi = GHI;
                            add(b, c, def, ghi);
                            if (c == 1 && b == 10 - a) {
                                cout << A << "+" << B << "/" << C << "+" << DEF << "/" << GHI << "=" << 10 << endl;
                                count++;
                            }
                        }
                    }
                }
            }
        }
    }
    cout << count << endl;
    return 0;
}
View Code

四、    快速排序

快速排序的partition过程,基本算法是很重要的。

swap(a,p,j);

五、    抽签

看到题目,第一反应,这肯定是个递归,蒙蒙看,看终止条件K==N,输出条件m==0,

第一次试,f(a,k+1,m-1,b); 不对。

第二次试,f(a,k+1,m-j,b); 半分钟解决。。。。

其实仔细看下,也很简单,k表示第几个国家,m表示当前还剩多少空位。当然实际循环里,添加进去b数组的不止5个,多出来的,b[M] = 0; 都给砍掉了。

f(a,k+1,m-j,b);

六、方格填数

1580

    #include <iostream>
    
    #include <stdio.h>
    
    #include <algorithm>
    
    using namespace std;
    
    int f1(int a[][6], int x, int y) {
    
        for (int i = x - 1; i <= x + 1; i++)
    
            for (int j = y - 1; j <= y + 1; j++) {
    
                if (i == x && y == j)continue;
    
                if (a[x][y] + 1 == a[i][j] || a[x][y] - 1 == a[i][j])return 1;
    
            }
    
        return 0;
    
    }
    
    int f2(int x, int y) {
    
        if (x == y + 1 || x == y - 1 || x == y)return 1;
    
        return 0;
    
    }
    
    int main() {
        int a[5][6] = { -2 };
            int count = 0;
        for (int a0 = 0; a0 <= 9; a0++) {
            for (int a1 = 0; a1 <= 9; a1++) {
                if (f2(a0, a1))continue;
                         for (int a2 = 0; a2 <= 9; a2++) {
                        if (a2 == a0 || f2(a2, a1))continue;
                                            for (int a3 = 0; a3 <= 9; a3++) {
    
                        if (a3 == a2 || a3 == a1 || f2(a3, a0))continue;
    
                        for (int a4 = 0; a4 <= 9; a4++) {
    
                            if (f2(a4, a3) || a4 == a2 || f2(a4, a1) || f2(a4, a0))continue;
    
                            for (int a5 = 0; a5 <= 9; a5++) {
    
                                if (f2(a5, a4) || a5 == a3 || f2(a5, a2) || f2(a5, a1) || f2(a5, a0))continue;
    
                                for (int a6 = 0; a6 <= 9; a6++) {
    
                                    if (f2(a6, a5) || a6 == a4 || a6 == a3 || f2(a6, a2) || f2(a6, a1) || a6 == a0)continue;
    
                                    for (int a7 = 0; a7 <= 9; a7++) {
    
                                        if (a7 == a6 || a7 == a5 || f2(a7, a4) || f2(a7, a3) || a7 == a2 || a7 == a1 || a7 == a0)continue;
    
                                        for (int a8 = 0; a8 <= 9; a8++) {
    
                                            if (f2(a8, a7) || a8 == a6 || f2(a8, a5) || f2(a8, a4) || f2(a8, a3) || a8 == a2 || a8 == a1 || a8 == a0)continue;
    
                                            for (int a9 = 0; a9 <= 9; a9++) {
    
                                                if (f2(a9, a8) || a9 == a7 || f2(a9, a6) || f2(a9, a5) || f2(a9, a4) || a9 == a3 || a9 == a2 || a9 == a1 || a9 == a0)continue;
    
                                                count++;
    
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        cout << count << endl;    
    }                                        
View Code

 七、剪邮票

, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

 

这5个点一定是个连通图,BFS更好写。

核心思想:1. BFS判定给定的5个位置是否符合。

     2. 每层循环取不同值,避免重复

#include <iostream>
#include <queue>
using namespace std;

bool BFS(int a, int b, int c, int d, int e) {
    bool m[13] = {0};
    queue<int>q;
    m[b] = 1; m[c] = 1; m[d] = 1; m[e] = 1;
    q.push(a);
    while (!q.empty()) {
        int i = q.front(); q.pop();
        //向上走
         if ((i - 4) > 0 && m[i - 4] == 1) {
             m[i - 4] = 0;
             q.push(i - 4);
         }
         //向下走
         if ((i + 4) < 13 && m[i + 4] == 1) {
             m[i + 4] = 0;
             q.push(i + 4);
         }
         //向右走
         if (i != 4 && i != 8 && i + 1 < 13 && m[i + 1] == 1) {
             m[i + 1] = 0;
             q.push(i + 1);
         }
         //向左走
         if (i != 5 && i != 9 && i - 1 > 0 && m[i - 1] == 1) {
             m[i - 1] = 0;
             q.push(i - 1);
         }
    }
    for (int i = 1; i < 13; i++) if (m[i])return false;
    return true;
}

int main() {
    int a, b, c, d, e, res = 0;
    for (a = 1; a <= 8; a++) {
        for (b = a + 1; b <= 9; b++) {
                for (c = b + 1; c <= 10; c++) {
                        for (d = c + 1; d <= 11; d++) {
                                for (e = d + 1; e <= 12; e++) {
                                        if (BFS(a, b, c, d, e)) {
                                            printf("%d %d %d %d %d\n", a, b, c, d, e);
                                            res++;
                                        }    
                                }
                        }
                }
        }
    }
    cout << res << endl;
    return 0;
}
View Code

八、四平方和定理

(1)NC做法,四重循环,死求,能出来,但是时间上,完全不达标。

(2)三重循环:因为第四个数可以由 前三个数和输入的数相剪 得出,省去最后一个循环。效率提升就很显著了。

#include <iostream>
#include <math.h>
using namespace std;

int main() {
    int x, i, j, k;
    int sign = 1;
    cin >> x;
    double X = sqrt(x);
    for (i = 0; sign&&i <= X; i++) {
        for (j = i; sign&&j <= X; j++) {
            for (k = j; sign&&k <= X; k++) {
                double L = sqrt(x - i * i - j * j - k * k);
                if (L == (int)L) {
                    cout << i << " " << j << " " << k << " " << L << endl;
                    sign = 0;
                }
            }
        }
    }
    return 0;
}
View Code

(3)三重循环,将算过的数据存起来 + 剪枝:

#include <iostream>
#include <math.h>
using namespace std;

int main() {
    int x, i, j, k;
    int sign = 1;
    cin >> x;
    int *arr = new int[x];
    memset(arr, 0, x * sizeof(int));
    double X = sqrt(x);
    for (i = 0; sign&&i <= X; i++) {
        if (!arr[i]) arr[i] = i * i;//i^2没算过,就算好存起来
        for (j = i; sign&&j <= X; j++) {
            if (!arr[j]) arr[j] = j * j;//j^2没算过,就算好存起来
            int J = arr[i] + arr[j];
            if (J > x) break;//剪枝
            for (k = j; sign&&k <= X; k++) {
                if (!arr[k]) arr[k] = k * k;//k^2没算过,就算好存起来
                int K = J + arr[k];
                if (K > x) break;
                double L = sqrt(x - K);
                if (L == (int)L) {
                    cout << i << " " << j << " " << k << " " << L << endl;
                    sign = 0;
                }
            }
        }
    }
    return 0;
}
View Code

九、交换瓶子

一开始,觉得最快的应该是快速排序的交换过程,后来仔细想下,数据很特殊,最后有序情况下,就是a[i]=i;快速排序还是会进行很多次无用的交换。

就从前面往后直接找,所以下标是1的位置就应该放1号瓶子,以此类推。

正常是一次交换排好一个元素,想要一次排好两个元素,就得数据支持,比如 a [ i ] = j ; a [ j ] = i ;这个交换代码也是可以做到的,所以这就是最少的步数。

#include <iostream>
using namespace std;
 
int main()
{
    int n,a[10005];
    cin>>n;
    for(int i = 1; i <= n; i++)
        cin>>a[i];
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        while(a[i] != i)  //如果数值和下标不相等,直接交换
        {
            swap(a[i],a[a[i]]);
            ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}
View Code

十、最大比例

首先这个比例一定是 大于 1 ,小于 max/min 的 ,那我们就可以用这个 max/min 不断除以自身的最小素因子,来寻找答案。

思想:

1. 用最大的数 除以 最小的数,得到一个可能的最大比例(A/B)。

2. 从小到大进行遍历。

  • 如果第 i 个数乘以A/B小于第 i+1个数,继续乘A/B。
  • 如果大于第i+1个数,说明这个比例是不对的(大了),A和B分别除去自己的最小素因子。

3. 遍历一遍之后,会得到一个A/B。但这并不一定是答案,回到第二步,如果整个遍历都没有出现第二部的蓝色字段,出来的就是答案了。

 上面的这些过程,时间主要在找素因子上,我们可以分析得到,这个最大的素因子会出现的情况是:X=x^2,X除1以外只有x一个因子,X数值上接近10^12,简单说就是素数表准备到 一百万 就够用了。

#include <iostream>
#include <algorithm>
#include <set>
#include <vector>    
using namespace std;
typedef long long ll;
#define N 1000000 
int prime[80000];
int M[N+1];
//打素数表
void EulerSieve() {
    int count = 0;
    for (int i = 2; i <= N; i++) {
        if (M[i] == 0) {
            prime[count++] = i;
        }
        for (int j = 0; j < count && prime[j] * i <= N; j++) {
            M[i*prime[j]] = 1;
            if (i%prime[j] == 0)
                break;
        }
    }
}
ll getMinPrimefactor(ll x) {
    if (x < N&&M[x] == 0)return x;
    //不知道具体数字,循环终止写大点无所谓,不会做到后面的。
    for (int i = 0; i < 80000; i++) {
        if (prime[i] == 0)return x;
        if (x%prime[i] == 0)return prime[i];
    }

}

ll gcd(ll a, ll b) {
    return b ? gcd(b, a%b) : a;
}

void reduce(ll &x, ll &y) {
    ll g = gcd(x, y);
    x /= g; y /= g;
}
//分数除
void div(ll &x1,ll &y1,ll x2,ll y2) {
    y1 *= x2; x1 *= y2;
    reduce(x1, y1);
}
//分数乘
void mul(ll &x1, ll &y1, ll x2, ll y2) {
    y1 *= y2; x1 *= x2;
    reduce(x1, y1);
}
void check(ll &A,ll &B,set<ll>s,int &flag) {
    set<ll>::iterator it = s.begin();
    while (true) {
        ll a = *it++, b = 1;
        if (it == s.end()) return;
        while (a < *it) {
            mul(a, b, A, B);
        }
        if (a > *it) {
            B /= getMinPrimefactor(B);
            A /= getMinPrimefactor(A);
            flag = true;
            it--;
        }
        //if (a == *it) {
        //    cout << A << "/" << B << endl;
        //}
    }    
}
int main() {
    ll n, t;
    int flag = true;
    EulerSieve();
    cin >> n;
    set<ll>s;
    for (ll i = 0; i < n;i++)  {
        cin >> t;
        s.insert(t);
    }
    
    ll B = *s.begin(), A = *s.rbegin();
    reduce(A, B);
    while (flag) {
        flag = false;
        check(A,B,s, flag);
    }
    cout << A << "/" << B << endl;
    return 0;
}
View Code

 

posted @ 2019-02-20 20:28  czc1999  阅读(139)  评论(0编辑  收藏  举报