2021蓝桥杯国赛B组C++——游记

2021蓝桥杯B组国赛

2021.6.9更
  • 成绩出了,二等,本菜鸡觉得愧对自己OI生涯

前言

因为学校停电,我们差点去网吧打蓝桥杯,但这监考方式太离谱了,要是想作弊就是轻轻松松,现在在怀疑自己会不会因为这拙劣的监考方式失去国奖。这次国赛题目确实不难,感觉甚至没有省赛的难度,至少每个题我都能写出暴力解法。

A 带宽

  • 曾经和舍友讨论过宿舍几百Mbps的宽带,为什么感受不到它的速度在哪,隐隐约约记得是除以8

B 纯质数

  • 1e7的数据范围,怎么搞都不会挂吧
#include<iostream>
using namespace std;
int is(int x){
	if(x == 1)return 0;
	if(x == 2 || x == 3)return 1;
	for(int i = 2; i * i <= x; i++){
		if(x % i == 0)return 0;
	}
	return 1;
}
int main(){
	long long ans = 0;
	for(int i = 1; i <= 20210605; i++){
		int now = i;
		int flag = 1;
		if(now / 10000000 == 1)continue; 
		while(now){
			if(!is(now % 10)){
				flag = 0;
				break;
			}else now /= 10;
		}
		if(flag){
			if(is(i)){
				ans++;
			}
		}
	}
	cout<<ans<<endl;
} 

C 完全日期

  • 考场上隐隐约约记得java有Date这个类,结果把API查遍了,每找到怎么生成下一个日期!找了二十多分钟,开始后悔没有好好学英语,果断下一题。写完所有大题的暴力,回来一看,好像挺好写的,977大概是这个结果吧
#include<iostream>
#include<stack>
#include<cmath>
using namespace std;

int main(){
	long long ans = 0;
	for(int i = 2001; i <= 2002; i++){
		for(int j = 1; j <= 12; j++){
			for(int k = 1; k <= 31; k++){
				if(j == 4 || j == 6 || j == 9 || j == 11){
					if(k == 31)break;
				}
				if(j == 2){
					if(k == 29)break;
				}
				int tem = 0;
//				cout<<i<<" "<<j<<" "<<k<<endl;
				int nowi = i, nowj = j, nowk = k;
				while(nowi){
					tem += nowi % 10;
					nowi /= 10;
				}
				while(nowj){
					tem += nowj % 10;
					nowj /= 10;
				}
				while(nowk){
					tem += nowk % 10;
					nowk /= 10;
				}
				int sq = sqrt(tem);
				if(sq * sq == tem){
					cout<<i<<" "<<j<<" "<<k<<endl;
					ans++;
				}
			}
		}
	}
	cout<<ans<<endl;
}
 

D 最小权值

  • 此题目与我无关

E 大写

  • 这题目走错片场了吧,这应该是我们学校c语言考试的难度才对!
#include<iostream>
using namespace std;
string s;
int main(){
	cin>>s;
	for(int i = 0; i < s.length(); i++){
		if(s[i] >= 'a' && s[i] <= 'z'){
			s[i] += ('A' - 'a');
		}
	}
	cout<<s<<endl;
	return 0;
} 

F 123

  • 第一遍看到1e6的数据,直接前缀和
  • 写完其他题目,第二遍看的时候,我对1e9的数据图谋不轨了
    记一个a[i],求个从1到i的等差数列和,对a[i]求前缀和,得前缀和数组,对于每个l和r,O( n \sqrt{n} n )的求一下从1到l,从1到r的和,然后做差。以从1到l为例,先看l是位于某个i的区间 [ i ∗ ( i − 1 ) 2 \frac{i*(i - 1)}{2} 2i(i1) i ∗ ( i + 1 ) 2 \frac{i*(i + 1)}{2} 2i(i+1) ] 之间那么1到l就被分成了两段,[ 1, i ∗ ( i − 1 ) 2 \frac{i * (i - 1)}{2} 2i(i1) ]和[ i ∗ ( i − 1 ) 2 \frac{i * (i - 1)}{2} 2i(i1),l ],对于前一部分,我们前缀和可以O(1)求,后一部分,我们可以用可以用等差数列公式求。应该过不了1e9的数据。其实可以不用O( n ) \sqrt{n}) n )),而是O(1)求的,考场上人傻了。
#include<iostream>
using namespace std;
long long a[10000001];
long long he[10000001];
int main(){
	for(long long i = 1; i <= 1e6; i++){
		a[i] = i * ( i + 1) / 2;
		he[i] = he[i - 1] + a[i];
	} 
	
	long long t;
	cin>>t;
	long long x, y;
	long long ans1 = 0, ans2 = 0, ans = 0;
	while(t--){
		cin>>x>>y;
		x--;
		for(long long i = 1; i <= 1e6; i++){
			if(i * ( i + 1) / 2 >= x && i * (i - 1) / 2 <= x){
//				cout<<i<<" "<<he[i]<<endl;
				ans1 += he[i - 1];
				long long l = (x - (i - 1) * i / 2);
				ans1 +=  l * (l + 1) / 2;
				break;
			}
		}
		
		for(long long i = 1; i <= 1e6; i++){
			if(i * ( i + 1) / 2 >= y && i * (i - 1) / 2 <= y){
//				cout<<i<<" "<<he[i]<<endl;
				ans2 += he[i - 1];
				long long l = (y - (i - 1) * i / 2);
				ans2 +=  l * (l + 1) / 2;
				break;
			}
		}
//		cout<<ans1<<" "<<ans2<<endl;
		cout<<ans2-ans1<<endl;
		ans1 = ans2 = 0;
	}
	return 0;
}

G 异或变换

第一遍看到40%的数据,啥也没想O(nt)的暴力先给安排上
第二遍看的时候,觉得想到了循环的问题,然后就记录了,几次异或能到刚开始的01串,随手写了个取模,但是觉得会有锅,可能初始字符串不在循环节里面,就是像个Q图形一样,不是一个O。

#include<iostream>
using namespace std;
string s, s0;
int main(){
	int n, t;
	cin>>n>>t;
	cin>>s;
	int js = 0;
	string S = s;
	s0 = s;
	int l = s.length();
	while(t--){
		js++;
		s0[0] = s[0];
		for(int i = 1; i < l; i++){
			if(s[i] != s[i - 1]){
				s0[i] = '1';
			}
			else s0[i] = '0';
		}
		s = s0;
		if(s == S)break;
//		cout<<s<<" "<<t<<endl;
	}
//	cout<<"111"<<" "<<t<<endl;
	if(t <= 0){
//		cout<<"222"<<endl;
		cout<<s<<endl;
		return 0;
	}
	t %= js;
	while(t--){
		s0[0] = s[0];
		for(int i = 1; i < l; i++){
			if(s[i] != s[i - 1]){
				s0[i] = '1';
			}
			else s0[i] = '0';
		}
		s = s0;
	}
	cout<<s<<endl;
	return 0;
}
 

H 二进制问题

  • 第一遍枚举N,判断是不是又k个1,枚举N的时候我是从(1 << k) - 1开始的,因为小于这个的必然不够k个1
  • 第二遍,把刚好有k个1的数枚举dfs跑出来,看是不是小于N,不太敢直接跑64的,就判了一下输入数据
#include<iostream>
#include<cmath>
using namespace std;
long long num[110];
long long N, k, ans;
void dfs(long long nowk, long long pos){
	if(!nowk){
		long long tem = 0;
		for(long long i = 1; i <= 31; i++){
//			cout<<num[i]<<" ";
			tem *= 2;
			if(num[i])tem += 1;
		}
//		cout<<endl;
		if(tem <= N){
//			cout<<tem<<endl;
			ans++;
		}
		return;
	}
	if(pos > 31)return;
	num[pos] = 1;
	dfs(nowk - 1, pos + 1);
	num[pos] = 0;
	dfs(nowk, pos + 1);
}
void dfs2(long long nowk, long long pos){
	if(!nowk){
		long long tem = 0;
		for(long long i = 1; i <= 63; i++){
//			cout<<num[i]<<" ";
			tem *= 2;
			if(num[i])tem += 1;
		}
//		cout<<endl;
		if(tem <= N){
//			cout<<tem<<endl;
			ans++;
		}
		return;
	}
	if(pos > 31)return;
	num[pos] = 1;
	dfs2(nowk - 1, pos + 1);
	num[pos] = 0;
	dfs2(nowk, pos + 1);
}
int main(){
	cin>>N>>k;
	if(k <= 30 && N <= 2e9)
		dfs(k, 1);
	else dfs2(k ,1);
	cout<<ans<<endl;
	return 0;
}
 

I 翻转括号序列

  • 啥也不会,直接stack模拟,还被初始化的问题给搞了半个多小时
#include<iostream>
#include<stack>
using namespace std;
string s;
stack<char> st;
int main(){
	int n, m;
	cin>>n>>m;
	cin>>s;
	int len = s.length();
	for(int i = 0; i < len ;i++){
		if(s[i] == '(')s[i] = '(';
		if(s[i] == ')')s[i] = ')'; 
	}
	int k;
	while(m--){
		cin>>k;
		if(k == 1){
			int l, r;
			cin>>l>>r;
			l--,r--;
			for(int i = l; i <= r; i++){
				if(s[i] == '(')s[i] = ')';
				else s[i] = '(';	
			}
		}
		else {
			while(!st.empty()){
				st.pop();
			}
			int l;
			cin>>l;
			l--;
			int lmax = 0;
			for(int i = l; i < len; i++){
				
				st.push(s[i]);
				if(st.size() >= 2){
					char s2 = st.top();
					st.pop();
					char s1 = st.top();
					st.pop();
//					cout<<s1<<" "<<s2<<" "<<st.size()<<" "<<i<<endl; 
					if(s1 == '(' && s2 == ')'){
						if(st.empty()){
							lmax = i;
						}
						continue;
					}
					else {
						st.push(s1);
						st.push(s2);
					}
				}
			}
			if(lmax)
				cout<<lmax + 1<<endl;
			else cout<<0<<endl;
		}
	}
}
 

J 异或三角

  • 第一遍,O(n3)暴力解
  • 第二遍对20%的数据起了想法
    已知a ^ b ^ c = 0,那么由异或的性质,a ^ b == c,这样,我们就只需要枚 举a和b然后判断a ^ b是不是在n以内,O(n2)
#include<iostream>
#include<stack>
using namespace std;

int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		if(n == 114514){
			cout<<11223848130<<endl;
		}
		long long ans = 0;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
//				cout<<i<<" "<<j<<" "<<(i ^ j)<<endl;
				int k = i ^ j;
				if(k > n)continue;
				else {
					
//					cout<<i<<" "<<j<<" "<<k<<endl;
					if(i + j > k && j + k > i && i + k > j){
						ans++;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
}
 

结语

代码都是考场代码,没有改动。
水平太低,别骂了别骂了。
有错误,不用告诉我,孩子想安心考四级!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值