第十二届蓝桥杯国赛C++B组 赛后总结
Posted mp-ui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十二届蓝桥杯国赛C++B组 赛后总结相关的知识,希望对你有一定的参考价值。
本人一本菜鸡,意外获得省一进入国赛,唯一的遗憾就是没能公费旅游,今年因为疫情改为线上比赛,所以只能去学校的实验室比赛了。。。下面是我做的一些答案希望大佬不要喷
A. 带宽
送分题,1Mbps = 1/8 MB/S,所以直接除以8,得到答案25
B. 纯质数
纯暴力,答案是1903
从1
一直暴力遍历到20210605
太慢了,所以直接用DFS搜了。。
#include <bits/stdc++.h>
using namespace std;
int start = 1;
int _end = 20210605;
bool isZhi(int n){
if(n <= 1){
return 0;
}
for(int i = 2;i < n;++i){
if(n % i == 0){
return 0;
}
}
return 1;
}
bool isChunZhi(int n){
if(!isZhi(n)){
return 0;
}
int j = n;
while(j){
int k = j % 10;
if(!(k == 2 || k == 3 || k == 5 || k == 7)){
return 0;
}
j /= 10;
}
return 1;
}
int cnt = 0;
void dfs(int n){
if(n > _end){
return;
}
if(isZhi(n)){
++cnt;
cout << n << endl;
}
dfs(n * 10 + 2);
dfs(n * 10 + 3);
dfs(n * 10 + 5);
dfs(n * 10 + 7);
}
int main(){
dfs(0);
cout << cnt << endl;
return 0;
}
C. 完全日期
暴力遍历一趟,答案977
#include <bits/stdc++.h>
using namespace std;
int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int days1[] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
int year = 2001;
int month = 1;
int day = 1;
int ey = 2021;
int em = 12;
int ed = 31;
void nextDay(){
// 是不是闰年
if(year % 4 == 0){
if(day < days1[month]){
++day;
}else{
day = 1;
month++;
if(month > 12){
month = 1;
++year;
}
}
}else{
if(day < days[month]){
++day;
}else{
day = 1;
month++;
if(month > 12){
month = 1;
++year;
}
}
}
}
int main(){
int cnt = 0;
while(year < ey || (year == ey && (month < em) || (month == em && day <= ed))){
cout << year << " " << month << " " << day << " ";
int sum = 0;
int y = year;
while(y){
sum += y % 10;
y /= 10;
}
int m = month;
while(m){
sum += m % 10;
m /= 10;
}
int d = day;
while(d){
sum += d % 10;
d /= 10;
}
cout << sum << " ";
double ss = sqrt(sum);
cout << ss << " ";
if((int)ss == ss){
++cnt;
cout << "是" << endl;
}else{
cout << "不是" << endl;
}
nextDay();
}
cout << cnt << endl;
return 0;
}
D. 最小权值
这题没了,大佬们猜的都是完全二叉树,就我猜的是结点全部都在左边。。算出来的答案很大很大,不说了。。。。
E. 大写
送分题
#include <bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s;
for(int i = 0;i < s.length();++i){
if(s[i] >= 'a' && s[i] <= 'z'){
s[i] -= 32;
}
}
cout << s << endl;
return 0;
}
F. 123
分段+二分,想了好久我也不知道对不对
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sum[1500000];
ll getn_np1(ll n){
return n * (n + 1) / 2;
}
//二分
ll get(ll n){
ll l = 1;
ll r = 1500000;
ll mid;
while(l < r){
mid = (l + r) >> 1;
ll n_np1 = getn_np1(mid);
if(n_np1 > n){
r = mid;
}else if(n_np1 < n){
l = mid + 1;
}else{
return mid;
}
}
return l;
}
void init(){
int i = 1;
ll summ = 0;
while(i < 1500000){
summ += i;
sum[i++] = summ;
}
}
int main(){
init();
int T;
cin >> T;
ll l,r;
while(T--){
cin >> l >> r;
ll p = get(l); //第几段
ll q = get(r); //第几段
ll pp = p * (p - 1) / 2; //第几段前面有几个数
ll ppp = l - pp; //段里面的第几个
ll qq = q * (q - 1) / 2;//第几段前面有几个数
ll qqq = r - qq; //段里面的第几个
ll res = 0;
if(p == q){
res = qqq * (qqq + 1) / 2 - ppp * (ppp - 1) / 2;
}else{
res = sum[p] - ppp * (ppp - 1) / 2;
res += qqq * (qqq + 1) / 2;
for(int i = p+1;i <q;++i){
res += sum[i];
}
}
//cout << p << " " << pp << " " << ppp << " " << q << " " << qq << " " << qqq << endl;
cout << res << endl;
}
return 0;
}
G. 异或变换
一开始是暴力做的,快交卷了才发现这个竟然是周期的,临时改了改,应该能骗点分吧!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,t,tt;
string s;
string ss;
cin >> n >> t;
cin >> s;
ss = s;
tt = t;
vector<string> v;
v.push_back(s);
while(t--){
for(int i = 1;i < n;++i){
ss[i] = ((s[i] - '0') ^ (s[i-1] - '0')) + '0';
}
s = ss;
if(s == v[0]){
ss = v[tt % v.size()];
break;
}
v.push_back(s);
}
cout << ss << endl;
return 0;
}
H. 二进制问题
大佬用数位DP(因为我不会),所以我只想到DFS,只要固定好1的个数就行了。应该能跑一半分,现场测试过,当N=2*1e9, K=30
的时候很快可以出结果,但是当N=2*1e9, K=10
的时候要跑几秒钟!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int bits[64];
ll cnt = 0;
//d:多少个二进制位
ll bin_to_dec(int d){
int i = 0;
int j = d - 1;
ll res = 0;
while(j >= 0){
if(bits[j] == 1){
res += pow(2,i);
}
--j;
++i;
}
return res;
}
//i-当前索引,n-最大值,k-一共多少个一,d-最多多少位,one-用了多少个1
void dfs(int i,ll n,int k,int d,int one){
if(one > k || one + d - i < k){
return;
}
if(one + d - i == k || one == k || i == d){
if(one + d - i == k){
for(int j = i;j < d;++j){
bits[j] = 1;
}
}
if(bits[0] == 0){
++cnt;
}else{
if(bin_to_dec(d) <= n){
++cnt;
}
}
/*
for(int i = 0;i<d;++i){
cout << bits[i];
}
cout << "->" << bin_to_dec(d) << endl;
*/
if(one + d - i == k){
for(int j = i;j < d;++j){
bits[j] = 0;
}
}
return;
}
bits[i] = 1;
dfs(i+1,n,k,d,one+1);
bits[i] = 0;
dfs(i+1,n,k,d,one);
}
int main(){
memset(bits,0,sizeof(bits));
ll n,k;
cin >> n >> k;
//判断需要多少个二进制位
double d = log(n) / log(2);
d = ceil(d);
dfs(0,n,k,d,0);
cout << cnt << endl;
return 0;
}
I. 翻转括号序列
这题我没有任何想法,纯暴力骗分,好像看到大佬用的是树状数组还是线段树?
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,m;
cin >> n >> m;
string s;
cin >> s;
int status;
ll l,r;
while(m--){
cin >> status >> l;
if(status == 1){
//第一种操作
cin >> r;
for(int i = l - 1;i<=r - 1;++i){
if(s[i] == '('){
s[i] = ')';
}else{
s[i] = '(';
}
}
//cout << s << endl;
}else if(status == 2){
//第二种操作
int tag = 0;
int i = l - 1;
int ma = 0;
while(i < s.length() && tag >= 0){
if(s[i] == '('){
++tag;
}else{
--tag;
}
if(tag == 0){
ma = max(ma,i + 1);
}
if(tag < 0){
break;
}
++i;
}
cout << ma << endl2021第十二届蓝桥杯国赛C/C++大学B组题解