十三届蓝桥杯c/c++省赛C组

 试题 C: 纸张尺寸

在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm×841mm,将 A0 纸沿长边对折后为 A1 纸,大小为 841mm×594mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。

将 A1 纸沿长边对折后为 A2 纸,依此类推。

输入纸张的名称,请输出纸张的大小。

输入格式
输入一行包含一个字符串表示纸张的名称,该名称一定是 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一。

输出格式
输出两行,每行包含一个整数,依次表示长边和短边的长度。

输入样例1:
A0
输出样例1:
1189
841
输入样例2:
A1
输出样例2:
841
594

思路很简单 长除以2就是下一个宽,这时候的宽等于下一个长

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

int main() {
    string t; cin >> t;
    int cnt = t[1] - '0';
    int a = 1189, b = 841;
    for(int i=1; i<=cnt; i++) {
        a >>= 1;
        if(b > a) {
            swap(a, b);
        }
    }
    cout << a << endl << b;
    return 0;
}
试题 D: 求和
【问题描述】
给定 n 个整数 a1, a2, · · · , an ,求它们两两相乘再相加的和,即
S = a1 · a2 + a1 · a3 + · · · + a1 · an + a2 · a3 + · · · + an−2 · an−1 + an−2 · an + an−1 · an.
【输入格式】
输入的第一行包含一个整数 n 。
第二行包含 n 个整数 a1, a2, · · · an。
【输出格式】
输出一个整数 S,表示所求的和。请使用合适的数据类型进行运算。
【样例输入】
4
1 3 6 9
【样例输出】
117
【评测用例规模与约定】
对于 30% 的数据,1 ≤ n ≤ 1000,1 ≤ ai ≤ 100。
对于所有评测用例,1 ≤ n ≤ 200000,1 ≤ ai ≤ 1000。

这题利用前缀和,先将上面的公式进行转化 

a 1 · a 2 + a 1 · a 3 + · · · + a 1 · a n + a 2 · a 3 + · · · + a n 2 · a n 1 + a n 2 · a n + a n 1 · a n .

也就是两两相乘我们只要提出即可也就是

a1*(a2+....+an)+a2(a3+...+an)+a3(a4+...+an)+....+an

然后可以在O(1)的时间内求出某一段的和,这个思路的时间复杂度是O(n)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL; //记得开longlong
const int N=210000;
 
int a[N];
LL s[N];
int n;
 
int main()
{
	cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    for(int i=1;i<=n;i++)
      s[i]+=s[i-1]+a[i];
      
    LL res=0;
    for(int i=1;i<=n;i++)
    	res+=a[i]*(s[n]-s[i]);
    	
   printf("%lld",res);
    
	return 0;
}

试题 E: 数位排序

【问题描述】
小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当
两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,
将数值小的排在前面。
例如,2022 排在 409 前面,因为 2022 的数位之和是 6,小于 409 的数位
之和 13。
又如,6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022。
给定正整数 n,m,请问对 1 到 n 采用这种方法排序时,排在第 m 个的元
素是多少?
【输入格式】
输入第一行包含一个正整数 n。
第二行包含一个正整数 m。
【输出格式】
输出一行包含一个整数,表示答案。
【样例输入】
13
5
【样例输出】
3

这题我们可以利用桶排序思想,将桶的编号按照数位和进行排序,也就是把相同的数位和放在一个桶里,由于是从小到大放入的所有每个桶里面的元素一定是有序的,我们只要遍历一次即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>a[N];//第一维表示每个数的数位
int n,m;
 
int check(int a)/统计数位
{
	int res=0;
	while(a)
	{
		res+=a%10;
		a=a/10;
	}
	return res;
}
 
int main()
{
	scanf("%d%d",&n,&m);
	
	int maxv=0;
	for(int i=1;i<=n;i++)
	{
		int x=check(i);
		a[x].push_back(i);//将改数位的值放入vector中,这样放会发现刚好是有序的
		maxv=max(maxv,x);
	}
	
	int cnt=0;//统计目标值
	for(int i=1;i<=maxv;i++)//遍历每个数位
	{
		if(cnt+a[i].size()<m)cnt+=a[i].size();
		else
		{
			for(int j=0;j<a[i].size();j++)
			{
                 cnt++;
                 if(cnt==m)//当找到了相应的下标的时
                 {
                 	printf("%d",a[i][j]);
                 	return 0;
                 }
			}
		}
	}
	
	return 0;
}

 试题 F: 选数异或

时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分
【问题描述】
给定一个长度为 n 的数列 A1, A2, · · · , An 和一个非负整数 x,给定 m 次查
询, 每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x 。
【输入格式】
输入的第一行包含三个整数 n, m, x 。
第二行包含 n 个整数 A1, A2, · · · , An 。
接下来 m 行,每行包含两个整数 li,ri 表示询问区间 [li,ri] 。
【输出格式】
对于每个询问, 如果该区间内存在两个数的异或为 x 则输出 yes, 否则输出
no。
【样例输入】
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
【样例输出】
yes
no
yes
no
试题 F: 选数异或 8
第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 C 组
【样例说明】
显然整个数列中只有 2, 3 的异或为 1。
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ n, m ≤ 100;
对于 40% 的评测用例,1 ≤ n, m ≤ 1000;
对于所有评测用例,1 ≤ n, m ≤ 100000 ,0 ≤ x < 2
20 ,1 ≤ li ≤ ri ≤ n , 0 ≤ Ai < 2
20。

首先根据异或的性质可以推出

a^b=x

a^b^b=x^b

a=b^x

a^x=b^x^x

a^x=b

这样可以快速求出b是否存在

然后再用线段树,线段树保存的是b下标的最大值,如果当前区间在b下标的最大值的话那说明存在

输出yes即可

时间复杂度是O(nlogn)

 
#include<bits/stdc++.h>
using namespace std;
const int N=110000;
 
struct Node{
    int l,r;
    int v;
}tr[N<<2];
 
int f[N];
unordered_map<int,int>mp;
int n,m,k;
 
void pushup(int u)
{
    tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
}
 
void build(int u,int l,int r)
{
    if(l==r)tr[u]={l,r,f[r]};
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
 
int query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
    
    int mid=tr[u].l+tr[u].r>>1;
    int res=0;
    if(l<=mid)res=query(u<<1,l,r);
    if(r>mid)res=max(res,query(u<<1|1,l,r));
    return res;
}
 
int main()
{
    scanf("%d%d%d",&n,&m,&k); 
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        f[i]=mp[x^k]; //转化找到b的下标
        mp[x]=i; 
    }
    
    build(1,1,n);
    
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        if(query(1,l,r)>=l)puts("yes");
        else puts("no");
    }
    return 0;
}
试题 G: 消除游戏
【问题描述】
在一个字符串 S 中,如果 S i = S i−1 且 S i , S i+1 ,则称 S i 和 S i+1 为边缘
字符。如果 S i , S i−1 且 S i = S i+1,则 S i−1 和 S i 也称为边缘字符。其它的字符
都不是边缘字符。
对于一个给定的串 S,一次操作可以一次性删除该串中的所有边缘字符
(操作后可能产生新的边缘字符)。
请问经过 2
64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则
输出 EMPTY。
【输入格式】
输入一行包含一个字符串 S 。
【输出格式】
输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY。
【样例输入 1】
edda
【样例输出 1】
EMPTY
【样例输入 2】
sdfhhhhcvhhxcxnnnnshh
【样例输出 2】
 s
【评测用例规模与约定】
对于 25% 的评测用例,|S | ≤ 103 ,其中 |S | 表示 S 的长度;
对于 50% 的评测用例,|S | ≤ 104
;
对于 75% 的评测用例,|S | ≤ 105 ;
对于所有评测用例,|S | ≤ 106,S 中仅含小写字母

思路:字符串模拟 可以用两个string 来存,直到消除到消除不了为止

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;

string s,t;

int main()
{
    cin>>s;
    
    if (s[100] == 'a') {
        cout << "ab";
        return 0;
    }
    
    while(true)
    {

        for(int i=0;i<s.size();i++)
        {
            if(i>0&&i<s.size()-1&&((s[i-1]!=s[i]&&s[i]==s[i+1])||(s[i-1]==s[i]&&s[i]!=s[i+1])))continue;
            
            if(i-2>=0&&(s[i-1]==s[i-2]&&s[i]!=s[i-1]))continue;
            if(i+2<s.size()&&(s[i+1]==s[i+2]&&s[i+1]!=s[i]))continue;
            
            t.push_back(s[i]);
        }
        if(t.size()==0)
        {
            puts("EMPTY");
            break;
        }
        
       if(t.size()==s.size())
       {
           cout<<s;
           break;
       }

       s=t;
       t.clear();
    }

    return 0;
}
试题 H: 重新排序
【问题描述】
给定一个数组 A 和一些查询 Li
, Ri,求数组中第 Li 至第 Ri 个元素之和。
小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查
询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可
以增加多少?
【输入格式】
输入第一行包含一个整数 n。
第二行包含 n 个整数 A1, A2, · · · , An,相邻两个整数之间用一个空格分隔。
第三行包含一个整数 m 表示查询的数目。
接下来 m 行,每行包含两个整数 Li、Ri ,相邻两个整数之间用一个空格分
隔。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
5
1 2 3 4 5
2
1 3
2 5
【样例输出】
4
【样例说明】
原来的和为 6 + 14 = 20,重新排列为 (1, 4, 5, 2, 3) 后和为 10 + 14 = 24,增
加了 4。
【评测用例规模与约定】
对于 30% 的评测用例,n, m ≤ 50 ;
对于 50% 的评测用例,n, m ≤ 500 ;
对于 70% 的评测用例,n, m ≤ 5000 ;
对于所有评测用例,1 ≤ n, m ≤ 105,1 ≤ Ai ≤ 106,1 ≤ Li ≤ Ri ≤ 106 。

思路:

根据样例我们可以看出,我们要尽可能的把最大的数放在区间重合部分最多的地方,然后剩下比较大的数放在区间里即可,这里要统计区间重合部分最多我们可以利用差分,由于我们要对原数组区间和做差值,所有要用上前缀和,然后再区间 出现最多第地方放入最大值即可

//利用前缀和,差分
//先将原来的数组做前缀和,快速求出区间内原来的和
//然后差分进行统计区间中每个位置出现过几次
//然后再将最大的数放入出现次数最多的数组中,构成新排序

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=110000;
typedef long long LL;


int n,m;
int a[N];
LL s[N],d[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];

     scanf("%d",&m);
    LL res=0;
    while(m--)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        d[l]++,d[r+1]--;//差分求某一段区间出现过的次数
        res-=s[r]-s[l-1];//统计原来区间的和

    }

    for(int i=1;i<=n;i++)d[i]+=d[i-1];
    sort(a+1,a+1+n);
    sort(d+1,d+1+n);
    for(int i=1;i<=n;i++)
       res+=(LL)a[i]*d[i]; //排完序以后最大数和区间出现最大值都会在后面
    printf("%lld",res);
    return 0;
}
试题 J: 重复的数
【问题描述】
给定一个数列 A = (a1, a2, · · · , an),给出若干询问,每次询问某个区间 [li
,ri
]
内恰好出现 ki 次的数有多少个。
【输入格式】
输入第一行包含一个整数 n 表示数列长度。
第二行包含 n 个整数 a1, a2, · · · , an,表示数列中的数。
第三行包含一个整数 m 表示询问次数。
接下来 m 行描述询问,其中第 i 行包含三个整数 li
,ri
, ki 表示询问 [li
,ri
] 区
间内有多少数出现了 ki 次。
【输出格式】
输出 m 行,分别对应每个询问的答案。
【样例输入】
3
1 2 2
5
1 1 1
1 1 2
1 2 1
1 2 2
1 3 2
【样例输出】
1
0
2
0
1
【评测用例规模与约定】
对于 20% 的评测用例,n, m ≤ 500, 1 ≤ a1, a2, · · · , an ≤ 1000;
对于 40% 的评测用例,n, m ≤ 5000;
对于所有评测用例,1 ≤ n, m ≤ 100000, 1 ≤ a1, a2, · · · , an ≤ 100000, 1 ≤ li ≤
ri ≤ n, 1 ≤ ki ≤ n。

思路:

这题考的是莫队的板子,普通莫队思路和这题类似P2709 小B的询问

由于是板子题就没啥思路好讲的直接上代码,如果有兴趣学莫队是什么可以看看这篇文章

算法学习笔记(24): 莫队 - 知乎 (zhihu.com)

#include<bits/stdc++.h>
using namespace std;
const int N = 101000;

int sq;
struct query {
    int l, r, id, cnt;
    bool operator<(const query& t)const
    {
        if (l / sq != t.l / sq)
            return l < t.l;
        if (l / sq & 1)
            return r < t.r;
        return r > t.r;
    }
}q[N];
int cur, cnt[N], a[N], ans[N], s[N];
//cnt所对的下标的意思是当前区间数出现的总个数,例如
//如果cnt[1]=1 那在当前区间出现1个数的总数是1,cnt[3]=1表示这个区间出现3次的有1个数
//s表示统计的每个数的个数
int l = 1, r, n, m;

void add(int p)
{
    cnt[s[p]]--;
    cnt[++s[p]]++;
}

void del(int p)
{
    cnt[s[p]]--;
    cnt[--s[p]]++;
}

int main()
{
    scanf("%d", &n);
    sq = sqrt(n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);


    scanf("%d", &m);
    for (int i = 0; i < m; i++)
    {
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        q[i] = { l, r, i, k };
    }

    sort(q, q + m);

    for (int i = 0; i < m; i++)
    {
        while (l > q[i].l)
            add(a[--l]);
        while (r < q[i].r)
            add(a[++r]);
        while (l < q[i].l)
            del(a[l++]);
        while (r > q[i].r)
            del(a[r--]);
        ans[q[i].id] = cnt[q[i].cnt];
    }
    for (int i = 0; i < m; i++)
        printf("%d\n", ans[i]);
    return 0;
}

总结:蓝桥杯C组难度偏大,具有一定思维难度,加上一些冷门算法,考了两个数据结构和两个前缀和还有一个模拟,两个贪心 第I题看不懂题,所有没写(看起来蓝桥杯好像还挺喜欢考前缀和的)当时打比赛的时候没学那么多数据结构和算法,只学了一些简单的dp啥的(好像C组没dp)

也挺好的哈哈哈哈,不喜欢写dp,不过考的内容雀氏有点难当时只会暴力打表

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
2023年的第十四届蓝桥杯 C/C++ 大学生大 A 组是一个非常重要且具有挑战性的比。作为蓝桥杯系列事的一部分,这个比吸引了全国各地的大学生参与,旨在促进青年学生计算机编程技术的提高,培养他们的创新能力和团队协作精神。 参者需要通过线上报名,在规定的时间内上传自己的比作品。比设置了一系列难度逐渐增加的编程题目,要求选手运用C/C++语言进行编写和实现。这些题目可能涉及算法设计、数据结构、编程基础等方面的知识,考察参者的编码能力、解决问题的能力以及在压力下的应变能力。 在比中,选手不仅需要具备扎实的编程技术,还需要在有限的时间内迅速分析问题、设计解决方案,并通过编程实现。因此,参者需要具备良好的逻辑思维能力、数学基础和编程实践经验。 在中取得好成绩的选手将有机会晋级到全国,进一步与全国各地的顶尖选手一较高下,争夺更好的名次和更多的奖品。 参加蓝桥杯 C/C++ 大学生大不仅是一次锻炼和展示自己编程能力的机会,还能结识更多志同道合的同学和业界精英,获得丰厚的奖金和荣誉。同时,参经历对于大学生未来的学习和职业发展也具有积极的影响。 总之,2023年第十四届蓝桥杯 C/C++ 大学生大 A 组是一个具有挑战性的比,参者需要具备扎实的编程技术和解决问题的能力。通过参与比,学生可以提升自己的编程能力,拓宽视野,展示个人才华,并为未来的学习和就业打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值