2021年蓝桥杯B组C++第十二届国赛真题

准备国赛,冲冲冲! 

2021年蓝桥杯第十二届省赛及国赛真题 - 题库 - C语言网 (dotcpp.com)

参考文献

(4条消息) 2021第十二届蓝桥杯国赛B组题解(C/C++)_从 2001 年 1 月 1 日到 2021 年 12 月 31 日中,一共有 多少个完全日期_404name的博客-CSDN博客

(4条消息) 2021第十二届蓝桥杯国赛C/C++大学B组题解_蓝桥杯异或三角_Mr_渣渣辉的博客-CSDN博客

 带宽 

200Mbps  意思每秒传200Mb信息 ,题目要求问B,因此200Mb/8=25MB

纯质数 

 暴力枚举   答案1903

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
typedef pair<double,int> PII;
typedef long long ll;
#define x first 
#define y second 
int myhash[10];
bool iszhishu(int x)
{
	if(x==2||x==3||x==5)return true;
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0)return 0;
	}
	return 1;
}
int main()
{
	myhash[2]=myhash[3]=myhash[5]=myhash[7]=1;//标定每位是否是素数
	int i=2,cnt=0;
	for(;i<=20210605;i++)
	{
		if(iszhishu(i))
		{
			int x=i,flag=1;
			while(x)
			{//判断每一位是否质数 
				if(myhash[x%10]==0)
				{
					flag=0;
					break;
				}
				x/=10;
			}
			if(flag)cnt++;
		}
	}
	cout<<cnt;
	return 0;
}

完全日期 

 

暴力枚举 答案977
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
typedef pair<double,int> PII;
typedef long long ll;
#define x first 
#define y second 
int Months[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int getsum(int x)
{//计算x各位之和 
	int sum=0;
	while(x)
	{
		sum+=x%10;
		x/=10;
	}
	return sum;
}
bool check(int x)
{//判断x是否是完全平方数 
	double a=sqrt(x);
	double b=(int)a;
	if(a==b)return true;
	return false;
}
int main()
{
	int cnt=0;
	int sum=0;
	for(int year=2001;year<=2021;year++)
	{
		for(int month=1;month<=12;month++)
		{
			
			int Days=Months[month];
			if(month==2&&(year%4==0&&year%100!=0)||year%400==0)
			Days++;//判断闰二月
			for(int day=1;day<=Days;day++)
			{
				sum=getsum(year)+getsum(month)+getsum(day);
				if(check(sum))cnt++;
			} 
		}
	}
	cout<<cnt;
	return 0;
}

最小权值 

大写

签到题

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
typedef pair<double,int> PII;
typedef long long ll;
#define x first 
#define y second 
int main()
{
	string str;
	cin>>str;
	int n=str.size();
	for(int i=0;i<n;i++)
	{
		if(str[i]>='a'&&str[i]<='z')str[i]-=32;
	} 
	cout<<str;
	return 0;
}

123

前缀和模板提  但数据范围很大 数组开不出来  考场上也就能开多大开多大了    45%通过

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e7+10;
typedef pair<double,int> PII;
typedef long long ll;
#define x first 
#define y second 
int arr[MAX],sum[MAX];
int main()
{
//	1  1,2  1,2,3  1,2,3,4   1,2,3,4,5
	int cnt=1;
	for(int i=1;i<MAX;i++)
	{
		for(int j=1;j<=i;j++)
		{
			arr[cnt]=j;
			sum[cnt]=sum[cnt-1]+j;
			cnt++;
			if(cnt>=MAX-1)
			{//防溢出 
				i=MAX+5;				
				break; 
			}
		}
	}
	int t,left,right;
	cin>>t;
	while(t--)
	{
		cin>>left>>right;
		cout<<sum[right]-sum[left-1]<<endl;
	}
	return 0;
}

思维优化   

把123数列想成金字塔型结构

1

12

123

1234

12345

所以计算left 到 right 需要先找出left,right在那一层的第几个 ,则需要计算中间和

我们可以用一个sum1[i]存储前i层的前缀和  ,sum2[j]存储123..n数列前缀和,(范围可以存)

则中间和计算就是三部分 left所在层剩下的(sum2计算) + 中间层和(sum1计算)  +right所咋层开头的(sum2计算)  

91% 部分数据超时 还是不能AC  各位找到好方法说一下

#include<bits/stdc++.h>
using namespace std;
const int MAX=3e6+10;
typedef pair<double,int> PII;
typedef long long ll;
#define x first 
#define y second 
ll sum1[MAX],sum2[MAX];
//1 3 6 10 
void getLevel(ll &lev,ll &ind,ll index)
{
	int l=1,r=MAX; 
	while(l<r)//二分优化找层数 
	{//计算index在那一层:递增层数level,前level层数量(等差公式)>index停下 
		ll mid=(l+r)/2;
		if((1+mid)*mid/2<index)l=mid+1;
		else r=mid;
	}
	lev=l;//index所在层数
	ll num_lev=(1+lev-1)*(lev-1)/2; //lev层之上数目 
	ind=index-num_lev;//index在levl层的第几个 
}
ll solve(ll left,ll right)
{
	ll lev1,lev2,ind1,ind2;
	getLevel(lev1,ind1,left);
	getLevel(lev2,ind2,right);
	ll s1=sum2[lev1]-sum2[ind1-1];//计算left所在层剩余数
	ll s2=sum1[lev2-1]-sum1[lev1];//计算隔断中间层的和 
	ll s3=sum2[ind2];
	return s1+s2+s3;
}
int main()
{
	for(ll i=1;i<MAX;i++)
	{
		sum2[i]+=sum2[i-1]+i;//计算123..n数列前缀和 
		sum1[i]=(1+i)*i/2+sum1[i-1];//计算各层前缀和 (1 3 6 10 15 21...数列) 
	}
	ll t,left,right;
	cin>>t;
	while(t--)
	{
		scanf("%lld%lld",&left,&right);
		cout<<solve(left,right)<<endl;
	}
	return 0;
}

异或变换 

找规律 2^r循环 +t要开long long

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=2e5+10;
int n;
int pow2[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
char arr[MAX];
int main()
{
/* 规律:长度为n,2^l<n<=2^r   则以2^r为循环(大于等于n的最小的2的幂次) 
10110  0
11101  1
10011
11010
10111
11100
10010
11011
10110   8
11101   9
10011*/
    ll t;
    cin>>n>>t;
    int circulation;
    for(int i=1;i<=n;i++)cin>>arr[i];
    for(int i=0;i<15;i++)
    {
        if(pow2[i]>=n)
        {
            circulation=pow2[i];
            break;
        }
    }
    int last=0;
    t%=circulation;
    for(int i=0;i<t;i++)
    {
        last=arr[1]-'0';
        for(int j=2;j<=n;j++)
        {
            int temp=arr[j]-'0';
            arr[j]='0'+last^(arr[j]-'0');
            last=temp;
        }
    }
    for(int j=1;j<=n;j++)cout<<arr[j];
    cout<<endl;
    return 0;
}

二进制问题

暴力骗分 55%

听说数位dp可以做,但我没学,各位自学吧

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=2e5+10;
//1011011
int count(ll x)
{
	int cnt=0;
	while(x)
	{
		if(x&1)cnt++;
		x>>=1;
	}
	return cnt;
}
int main()
{
	ll n;
	int k;
	cin>>n>>k;
	ll res=0;
	for(ll i=1;i<=n;i++)
	{
		if(count(i)==k)res++;
	}
	cout<<res; 
    return 0;
}

翻转括号序列

 模拟水数据

//模拟水数据
#include <bits/stdc++.h>
using namespace std;
string s;
void rev(int l,int r){
    for(int i=l;i<=r;i++){
        if(s[i]=='('){
            s[i]=')';
        }else{
            s[i]='(';
        }
    }
}
int check(int l){
    if(s[l]==')')return 0;
    stack<char>stk;
    stk.push('(');
    int mark=0;
    for(int i=l+1;i<s.size();i++)
    {
    	if(s[i]==')'&&stk.size())
    	{
    		stk.pop();
    		if(stk.size()==0)mark=i+1;
		}
    	else if(s[i]=='(')stk.push('(');
    	else if(s[i]==')'&&stk.size()==0)return mark;
	}
    return mark;
}
int main(){
    int n,m;
	cin>>n>>m;
        cin>>s;
        while(m--){
            int op,l,r;
            scanf("%d",&op);
            switch(op){
                case 1:
                    scanf("%d %d",&l,&r);
                    rev(l-1,r-1);
                    break;
                case 2:
                    scanf("%d",&l);
                    printf("%d\n",check(l-1));
                    break;
            }
        }
return 0;
}

异或三角 

 三层枚举骗分

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=2e5+10;
int main()
{

	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		ll cnt=0;
		for(ll i=1;i<=n;i++)
		{
			for(ll j=1;j<=n;j++)
			{
				for(ll k=1;k<=n;k++)
				{
					if((i^j^k)==0)
					{
						if(i+j>k&&i+k>j&&j+k>i)
						{
							cnt++;
						}
					}
				}
			}
		}
		cout<<cnt<<endl;
	}
	
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值