准备国赛,冲冲冲!
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![](https://img-blog.csdnimg.cn/20210605152713886.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzU4OTYw,size_16,color_FFFFFF,t_70#pic_center)
前缀和模板提 但数据范围很大 数组开不出来 考场上也就能开多大开多大了 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;
}