蓝桥2014年省赛A组题目题解

填空题

猜年龄

在这里插入图片描述
正确答案:

10
#include <bits/stdc++.h>
using namespace std;
int main()
{
    bool ok = true;
    int x, y;
    for(int i = 9; ok; i++)
    {
        for(int j = i - 8; j < i; j++)
        {
            if(i*j == (i+j)*6)
            {
                ok = false;
                x = i, y = j;
            }
            if(!ok) break;
        }
    }
    printf("%d %d\n",x,y);
    return 0;
}

切面条

在这里插入图片描述
正确答案:

1025

1 + 2 n 2^n 2n n n n 表示对折次数


神奇算式

在这里插入图片描述
正确答案:

12
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int ans = 0;
    for(int i = 102; i < 999; i++)
    {
        int t = i;
        set<int>s; s.clear();
        while(t > 0) s.insert(t%10), t/= 10;
        if(s.size() != 3) continue;
        for(int j = 1; j <= 9; j++)
        {
            if(s.find(j) != s.end()) continue;
            int temp = i*j;
            if(temp < 1023  || temp > 9876) continue;
            set<int>one;
            one.clear();
            while(temp > 0) one.insert(temp%10), temp /= 10;
            vector<int> v; v.clear();
            for(set<int>:: iterator it = s.begin(); it != s.end(); it++) v.push_back(*it);
            v.push_back(j);
            int ok = 1;
            for(int k = 0; k < 4; k++)
                if(one.find(v[k]) == one.end()) ok = 0;
            if(ok)
            {
                ans++;
                cout<<i<<" "<<j<<endl;
            }
        }
    }

    set<int>c; c.clear();
    for(int i = 10; i < 99; i++)
    {
        int t = i;
        set<int>s;
        s.clear();
        while(t > 0) s.insert(t%10), t/= 10;
        if(s.size() != 2) continue;
        for(int j = 10; j < 99; j++)
        {
            int a = j%10, b = j/10;
            if(a == b || s.find(a) != s.end() || s.find(b) != s.end()) continue;
            int temp = i*j;
            if(temp < 1023  || temp > 9876) continue;
            set<int>one;
            one.clear();
            while(temp > 0) one.insert(temp%10), temp /= 10;
            vector<int> v; v.clear();
            for(set<int>:: iterator it = s.begin(); it != s.end(); it++) v.push_back(*it);
            v.push_back(a); v.push_back(b);
            int ok = 1;
            for(int k = 0; k < 4; k++)
                if(one.find(v[k]) == one.end()) ok = 0;
            if(ok)
            {
                if((c.find(i) != c.end() && c.find(j) != c.end()) || i == j) continue;
                ans++;
                cout<<i<<" "<<j<<endl;
                c.insert(i); c.insert(j);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

史丰收速算

在这里插入图片描述
正确答案:

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

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* mod)
{
    char* level[] = {
        "142857",
        "285714",
        "428571",
        "571428",
        "714285",
        "857142"
    };  //多位数超过 n/7 就要进 n

    char buf[7];
    buf[6] = '\0';
    strncpy(buf, mod, 6);  //将mod这个字符串拷贝到buf中

    int i;
    for(i = 5; i >= 0; i--){
        int tr = strcmp(level[i], buf);  //从后往前,依次取 level中的串和buf比较
        if(tr < 0) return i + 1;  //buf更大
        while(tr == 0){  //buff 和 level相等
            mod += 6;  //往后偏移 6 位
            strncpy(buf, mod, 6); //再拷贝 6 个字符到 buf中
            tr = strcmp(level[i], buf); //再比较
            if(tr < 0) return i + 1;
            if(tr > 0) return i;  //填代码
        }
    }
    return 0;
}
//多位数乘以 7
void f(char* s)   //s代表多位数
{
    int head = jin_wei(s);  //head是s的进位
    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()
{
    //4285711*7
    f("4285711");
    return 0;
}

锦标赛

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
//重新决出 k 号位置, v 为已输出值
//a 原始数据  b是树, n = 31 k = 0 是下标, v是·第一大的值的下标
void pk(int* a, int*b, int n, int k, int v)
{
    int k1 = k*2 + 1;  //k 的左子下标
    int k2 = k1 + 1;   //右子下标
    if(k1 >= n || k2 >= n){ //超过树的边界, k一定是叶子
        b[k] = -1;
        return ;
    }
//延着冠军的路一直追溯到第一次比赛
    if(b[k1] == v)
        pk(a, b, n, k1, v);
    else
        pk(a, b, n, k2, v);
//到此,k 就是冠军一开始的下标,此时 b[k] = -1;
    //重新比较
    if(b[k1] < 0){
        if(b[k2] >= 0)
            b[k] = b[k2];
        else
            b[k] = -1;
        return ;
    }

    if(b[k2] < 0){
        if(b[k1] >= 0)
            b[k] = b[k1];
        else
            b[k] = -1;
        return;
    }

    if(a[b[k1]] > a[b[k2 ]])    //填空
        b[k] = b[k1];   //记录下标,存的下标
    else
        b[k] = b[k2];
}

//对a中数据,输出最大,次大元素位置和值
void f(int* a, int len)
{
    int n = 1;
    while(n < len) n *= 2;
    // n = 16 len = 9
    //开辟树的空间
    int* b = (int*)malloc(sizeof(int*)*(2*n-1));
    int i;
    //初始化树的最下层 满二叉树
    for(i = 0; i < n; i++){
        if(i < len)
            b[n-1+i] = i;
        else
            b[n-1+i] = -1;
    }
    //从最后一个向前处理 2*n - 1- 1是 b数组的最大下标
    for(i = 2*n -1 - 1; i > 0; i -= 2){
        if(b[i] < 0){ //i 一开始一定指向右孩子
            if(b[i-1] >= 0)  //左子树大
                b[(i-1)/2] = b[i-1];  //右孩子
            else   //两个孩子都是 -1
                b[(i-1)/2] = -1;
        }
        else{ //自己的值大于0
            if(a[b[i]] > a[b[i-1]]) //右孩子大
                b[(i-1)/2] = b[i];
            else  //左孩子大
                b[(i-1)/2] = b[i-1];
        }
    }

    //输出根
    printf("%d : %d\n",b[0],a[b[0]]);

    //值等于根元素的需要重新 pk
    pk(a, b, 2*n-1, 0, b[0]);
    //再次输出树根
    printf("%d : %d\n",b[0],a[b[0]]);
    free(b);
}
int main()
{
    int a[] = {154, 55, 18, 16, 122, 17, 130, 9, 58};
    f(a,9);
    return 0;
}

扑克序列

在这里插入图片描述
正确答案:

2342A3A4
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool check(const string &s)
{
    if(s.rfind('A')-s.find('A') == 2 &&
            s.rfind('2') - s.find('2') == 3 &&
            s.rfind('3') - s.find('3') == 4 &&
            s.rfind('4') - s.find('4') == 5)
                return true;
    return false;
}
int main(int argc,const char* argv[])
{
    string s = "223344AA";
    do{
        if(check(s)) cout<<s<<endl;
    }while(next_permutation(s.begin(),s.end()));
    return 0;
}

编程题

蚂蚁感冒

题目链接
题目大意
长 100 厘米的细长直杆子上有 n n n 只蚂蚁。它们的头有的朝左,有的朝右。
  每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。
  当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
  这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。
  请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入格式
第一行输入一个整数 n n n (1 < n n n < 50), 表示蚂蚁的总数。
接着的一行是n个用空格分开的整数 X i X_i Xi (-100 < X i X_i Xi < 100), X i X_i Xi 的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现 0 值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。
输出格式
要求输出 1 个整数,表示最后感冒蚂蚁的数目。
输入样例

5
-10 8 -12 25 -20

输出样例

3

在这里插入图片描述

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
    int n,x;
    scanf("%d %d",&n,&x);
    int l = 0, r = 0;
    for(int i = 1; i < n; i++)
    {
        int t;
        scanf(" %d",&t);
        if(abs(x) < abs(t) && t < 0) r++;
        if(abs(x) > abs(t) && t > 0) l++;
    }
    printf("%d\n",l+r+1);
    return 0;
}

地宫取宝

题目链接
题目大意
X 国王有一个地宫宝库。是 n x m n x m nxm 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
  小明被带到地宫的入口,国王要求他只能向右或向下行走。
  走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
  当小明走到出口时,如果他手中的宝贝恰好是 k k k 件,则这些宝贝就可以送给小明。
  请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k k k 件宝贝。
输入格式
输入一行 3 个整数,用空格分开: n n n m m m k k k (1 ≤ n , m ≤ 50 \leq n,m \leq 50 n,m50, 1 ≤ k ≤ 12 1 \leq k \leq 12 1k12)
接下来有 n n n 行数据,每行有 m m m 个整数 C i C_i Ci ( 0 ≤ C i ≤ 12 0 \leq C_i \leq 12 0Ci12)代表这个格子上的宝物的价值
输出格式
要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
输入样例

2 3 2
1 2 3
2 1 5

输出样例

14
#include <iostream>
#include <cmath>
using namespace std;
const int mod = 1000000007, N = 55;
int main()
{
    int f[N][N][15][15] = {0};
    int a[N][N];
    int n,m,k;
    cin>>n>>m>>k;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) cin>> a[i][j], a[i][j] ++;   //1~13

    f[1][1][0][0] = 1; f[1][1][1][a[1][1]] = 1;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            for(int cnt = 0; cnt <= k; cnt++)
                for(int v = 0; v <= 13; v++)
                {
                    f[i][j][cnt][v] = (f[i][j][cnt][v] + f[i-1][j][cnt][v])%mod;
                    f[i][j][cnt][v] = (f[i][j][cnt][v] + f[i][j-1][cnt][v])%mod;
                    if(cnt && v == a[i][j])
                        for(int z = 0; z < v; z++)
                        {
                            f[i][j][cnt][v] = (f[i][j][cnt][v] + f[i][j-1][cnt-1][z])%mod;
                            f[i][j][cnt][v] = (f[i][j][cnt][v] + f[i-1][j][cnt-1][z])%mod;
                        }
                }
    int res = 0;
    for(int i = 1; i <= 13; i++) res = (res + f[n][m][k][i])%mod;
    cout<<res<<'\n';
    return 0;
}

斐波那契

题目链接
题目大意
斐波那契数列大家都非常熟悉。它的定义是:
   f ( x ) f(x) f(x) = 1 … ( x = 1 , 2 x=1,2 x=1,2)
   f ( x ) f(x) f(x) = f ( x − 1 ) f(x-1) f(x1) + f ( x − 2 ) f(x-2) f(x2) … ( x > 2 x>2 x>2)
  对于给定的整数 n n n m m m,我们希望求出:
   f ( 1 ) + f ( 2 ) + . . . + f ( n ) f(1) + f(2) + ... + f(n) f(1)+f(2)+...+f(n) 的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
  公式如下
在这里插入图片描述
  但这个数字依然很大,所以需要再对 p p p 求模。
输入格式
输入为一行用空格分开的整数 n n n m m m p p p ( 0 < n , m , p < 1 0 18 0 < n, m, p < 10^{18} 0<n,m,p<1018)
输出格式
输出为1个整数,表示答案
输入样例

2 3 5

输出样例

25

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

ll p;

ll qmul(ll a, ll b)
{
    ll res = 0;
    while (b)
    {
        if (b & 1) res = (res + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return res;
}

void mul(ll c[][2], ll a[][2], ll b[][2])  // c = a * b
{
    static ll t[2][2];
    memset(t, 0, sizeof t);

    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            for (int k = 0; k < 2; k ++ )
                t[i][j] = (t[i][j] + qmul(a[i][k], b[k][j])) % p;

    memcpy(c, t, sizeof t);
}

ll F(ll n)
{
    if (!n) return 0;

    ll f[2][2] = {1, 1};
    ll a[2][2] = {
        {0, 1},
        {1, 1},
    };

    for(ll k = n - 1; k; k >>= 1)
    {
        if (k & 1) mul(f, f, a);  // f = f * a
        mul(a, a, a);  // a = a * a
    }

    return f[0][0];
}

ll H(ll m, ll k)  // (F(m - 1) * F(k) - 1) mod F(m)
{
    if (k % 2) return F(m - k) - 1;
    else
    {
        if (k == 0 || m == 2 && m - k == 1) return F(m) - 1;
        else return F(m) - F(m - k) - 1;
    }
}

ll G(ll n, ll m)  // (F(n) - 1) mod F(m)
{
    if (m % 2 == 0)  // m是偶数
    {
        if (n / m % 2 == 0)  // n / m 是偶数
        {
            //cout << n << ' ' << m << ' ' << F(n % m) << endl;
            if (n % m == 0) return F(m) - 1;
            else return F(n % m) - 1;
        }
        else  // n / m 是奇数
        {
            return H(m, n % m);
        }
    }
    else  // m 是奇数
    {
        if (n / m % 2 == 0 && n / 2 / m % 2 == 0)  // n / m 是偶数,n / (2m) 是偶数
        {
            if (n % m == 0) return F(m) - 1;
            else return F(n % m) - 1;
        }
        else if (n / m % 2 == 0 && n / 2 / m % 2)  // n / m 是偶数,n / (2m) 是奇数
        {
            if (m == 2 && n % m == 1) return F(m) - 1;
            else return F(m) - F(n % m) - 1;
        }
        else if (n / m % 2 && n / 2 / m % 2 == 0)  // n / m 是奇数,n / (2m) 是偶数
        {
            return H(m, n % m);
        }
        else  // n / m 是奇数,n / (2m) 是奇数
        {
            if (n % m % 2)
            {
                if (m == 2 && m - n % m == 1) return F(m) - 1;
                else return F(m) - F(m - n % m) - 1;
            }
            else
            {
                return F(m - n % m) - 1;
            }
        }
    }
}

int main()
{
    ll n, m;

    while(~scanf(" %lld%lld%lld",&n,&m,&p))
    {
        ll ans = (G(n + 2, m) % p + p) % p;
        printf("%lld\n",ans);
    }

    return 0;
}

波动数列

题目链接
题目大意
观察这个数列:
  1 3 0 2 -1 1 -2 …
  这个数列中后一项总是比前一项增加2或者减少3。
  栋栋对这种数列很好奇,他想知道长度为 n n n 和为 s s s 而且后一项总是比前一项增加 a a a 或者减少 b b b 的整数数列可能有多少种呢?
输入格式
输入的第一行包含四个整数 n n n s s s a a a b b b,含义如前面说述。
输出格式
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。
输入样例

4 10 2 3

输出样例

2

x x x x + p x+p x+p x + 2 p x+2p x+2p + … x + ( n − i ) p x+(n-i)p x+(ni)p = s s s
p p p = { + a +a +a − b -b b}
d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i 项和模 n n n 余数是 j j j,属性表示方案数。
状态转移方程:
d p [ i ] [ j ] = ( d p [ i − 1 ] [ ( ( j − i ∗ b ) % n ) + n % n ] + d p [ i − 1 ] [ ( ( j + i ∗ a ) % n ) + n % n ] ) % m o d dp[i][j] = (dp[i-1][((j-i*b)\%n)+n\%n] + dp[i-1][((j+i*a)\%n)+n\%n])\%mod dp[i][j]=(dp[i1][((jib)%n)+n%n]+dp[i1][((j+ia)%n)+n%n])%mod

#include <cstdio>
using namespace std;
typedef long long ll;
const ll maxn=1e3+7,mod=1e8+7;
ll dp[maxn][maxn];
ll work(int a,int b)
{
    return (a%b+b)%b;
}
int main()
{
    int n,s,a,b;
    scanf("%d%d%d%d",&n,&s,&a,&b);

    dp[0][0]=1;
    for(int i=1;i<n;++i)
        for(int j=0;j<n;++j){
            ll ta=work(j + i*a,n);
            ll tb=work(j - i*b,n);
            dp[i][j]=(dp[i-1][ta]+dp[i-1][tb])%mod;
        }
    ll t=work(s,n);
    printf("%lld\n",dp[n-1][t]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幸愉聊信奥

谢谢亲的支持,我会继续努力啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值