2018蓝桥杯国赛C/C++B组总结

本人大二,第一次参加蓝桥杯国赛,虽然有过一年多的acm经历,还是没有什么信心,本来想着水一个国三,没想到可以拿国一,这波不亏。

以下想法,答案不能保证正确,仅供参考。

A题   

题意:给你2张100元,要你换成5元,2元,1元的零钱,要求是2元的张数是1元的10倍,并且5元,2元,1元张数不能为0,都得有。

思路:简单题,列方程发现只有一个解,19张5元,50张2元,5张1元。

答案 : 74


B题   

题意:有一排n个烟花,要你来点有几种点法,要求是不能点两个连续的烟花。

比如当n=3,有5种点法。现在告诉你n=30,有几种点法?

思路:直接dfs搜即可。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
int sum = 0;
void dfs(int dep,int p)
{
    if(dep == 30){
        sum++;
        return;
    }
    if(p == 0){
        dfs(dep + 1,0);
        dfs(dep + 1,1);
    }
    else{
        dfs(dep + 1,0);
    }
}
int main()
{
    dfs(0,0);
    cout << sum << endl;
    return 0;
}

答案:2178309


C题   代码填空题

题意:是关于格雷码的题目,题意很长,主要意思是给你一个整数a,你要把它二进制1最先出现的位置的后一位更改(1变0,0变1)。比如,1101 -> 1111 , 01 -> 11,11 -> 01

思路:lowbite的知识。a & -a 可以得到类似于000100,其中1就是最先出现的1,其中原理模拟一遍就可得出。之后向后移一位再与a异或即可得到结果。

答案:((a & (-a)) << 1) ^ a


D题   程序设计题

题意:有一块电子表能显示0到n - 1,它有两个按键,分别能让时间加1和k(可循环),现在给你n和k,问你从任意时间调到任意时间有个最少操作数,要你输出所以最少操作数中最大的那一个。

输入:n  k

输出:按题目要求输出

样例

输入:5 3

输出:2

样例解析

距离  操作

0       0

1       1

2       1 + 1

3       3

4       1 + 3

最多两步,输出2

思路:我是dp做的,dp[i] = min(dp[(i - 1 + n) % n],dp[(i - k + n) % n]) + 1

答案:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define INF 10000000
using namespace std;
int dp[100008];
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k) != EOF){
        for(int i = 0;i <= n;i++){
            dp[i] = INF;
        }
        dp[0] = 0;
        int maxn = 0;
        for(int i = 1;i < n;i++){
            dp[i] = min(dp[(i - 1 + n) % n],dp[(i - k + n) % n]) + 1;
            maxn = max(maxn,dp[i]);
        }
        cout << maxn << endl;
    }
    return 0;
}

E题  程序设计题

题意:

思路:不会做

答案:听说是dp题,完全不会


F题  程序设计题

题意:给你一个n*n的矩阵,其中第i行第j列 a[i][j] = gcd(i,j) * gcd(i,j)

n=4时

1   1   1   1

1   4   1   4

1   1   9   1

1   4   1   16

现在给你一个n,要你输出矩阵内所有元素的和

输入:一个整数n(0 < n < 1e7)

输出:按题目要求输出

样例1

输入:4

输出:48

样例2

输入:6

输出:155

思路:易知矩阵上三角=下三角,主对角线好求,所有我们的任务主要是求上三角。

上三角 = 求和gcd(i,j)平方(1<= j <= n,1<= i < j)

现在我们来考虑这样一个问题,给你一个n要你求和gcd(i,n)(1 <= i < n)你会怎么求,正解就是先求出所有n的约数x,然后求和 x * euler[n / x](euler 是欧拉函数)。

来证明:设gcd(i,n) = x,那么gcd(i / x,n / x) = 1,说明x是n的约数,i / x 与n / x互质,也就是说对于这个x,它出现的次数为与n / x互质数的个数,即euler[n / x]。所以,对于这个约数x它对结果做的贡献 = x * euler[n / x]。

现在我们重新回到求上三角的问题中来,其实就是刚才问题的拓展,对于每个j求和gcd(i,j)平方(1 <= i < j) ,但我们不能对每个j求它的约数,会超时。那么我们就以约数为主,对一个数x,它是2x的约数,是3x的约数.....当循环到2x时,我们就要加上x * x * euler[2],到3x时,加上x *x * euler[3]....。所以x对结果的贡献就是 = x * x * (euler[2] + euler[3]....+euler[n / x])。我们可以预处理一个数组记录这个前euler和,这样时间复杂度就是O(n)了。

答案:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define LL long long
using namespace std;
const int maxn = 1e7+10;
const int mod = 1e9+7;
LL euler[maxn];
LL sum[maxn];
void Init()
{
    memset(euler,0,sizeof(euler));
    euler[1] = 1;
    for(int i = 2; i < maxn; i++)
    {
        if(!euler[i])
        {
            for(int j = i; j < maxn; j+=i)
            {
                if(!euler[j])
                    euler[j] = j;
                euler[j] = euler[j]/i*(i-1);
            }
        }
    }
    sum[1] = 0;
    for(int i = 2; i < maxn; i++)
        sum[i] = (sum[i-1]+euler[i])%mod;
}
int main()
{
    Init();
    int n;
    LL answer = 0;
    while(scanf("%d",&n)!=EOF){
        answer = 0;
        for(int i = 1; i <= n/2; i++)//求上三角
        {
            LL ans = i;//不能直接写i*i,会爆int
            ans = (ans * ans) % mod;
            answer = (answer+ans*sum[n/i])%mod;
        }
        answer = answer*2%mod;
        for(int i = 1; i <= n; i++)//求对角线
        {
            LL ans = i;
            ans = (ans * ans) % mod;
            answer = (answer+ans)%mod;
        }
        cout<<answer<<endl;
    }
    return 0;
}//田长宏编码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值