2021 The 12th Blue Bridge Cup Software Competition Final, National Competition, C/C++ University Group B Problem Solving

2021 The 12th Blue Bridge Cup Software Competition Final, National Competition, C/C++ University Group B Problem Solving

Supplementary link: address

insert image description here
This line segment tree question is not very easy to do, and the two binary dp questions (although both can be transferred by dfs) ​​are a bit troublesome.
If you are careless in the front, you can't find the law/conclusion formula, or if you haven't written the prefix, binary and binary tree, then send it.

Question 1 - Bandwidth (5 points)

insert image description here

  • Topic: Unit conversion between Mbps and MB, no one can't, no, no.
  • Answer: 25
#include<bits/stdc++.h>
using namespace std;

int main(){
    
    
    cout<<200/8;
    return 0;
}


Question 2 - Pure Prime Numbers (5 points)

insert image description here

  • The meaning of the question: A pure prime number is a number that is itself a prime number, and each digit is also a prime number. Find how many such numbers there are in 1-20210605.
  • Idea: Enumerate each number directly and violently, and disassemble it to judge whether it is right or not.
  • Answer: 1903
//T2
#include<bits/stdc++.h>
using namespace std;
int isprime(int x){
    
    
	if(x==1)return 0;
	for(int i = 2; i*i <= x; i++){
    
    
		if(x%i==0){
    
    
			return 0;
		}
	}
	return 1;
}
set<int>se;
int check(int x){
    
    
	int t = x;
	while(t){
    
    
		int r = t%10;
		if(!se.count(r))return 0;
		t = t/10;
	}
	return 1;
}
int main(){
    
    
	se.insert(2);
	se.insert(3);
	se.insert(5);
	se.insert(7);
	int cnt = 0;
	for(int i = 1; i <= 20210605; i++){
    
    
		if(isprime(i)){
    
    
			if(check(i)){
    
    
				cnt++;
			}
		}
	}
	cout<<cnt<<"\n";
	return 0;
}

Question 3 - Full Date (10 points)

insert image description here

  • Title meaning: Define the complete date representation, the sum of the digits of the year, month and day of a date is a complete square number. Find how many complete dates are between the given start and end dates.
  • Idea: Violently enumerate the date, and then judge whether it is right or not.
  • Answer: 977
//T3
#include<bits/stdc++.h>
using namespace std;
int days[13] = {
    
    0,31,28,31,30,31,30,31,31,30,31,30,31};
int main(){
    
    
	int cnt = 0;
	for(int y = 2001; y <= 2021; y++){
    
    
		if((y%100!=0&&y%4==0)||y%400==0){
    
    
			days[2] = 29;
		}else{
    
    
			days[2] = 28;
		}
		for(int m = 1; m <= 12; m++){
    
    
			for(int d = 1; d <= days[m]; d++){
    
    
				int s = 0;
				int yy=y, mm=m,dd=d;
				while(yy){
    
    s+=yy%10; yy/=10;}
				while(mm){
    
    s+=mm%10; mm/=10;}
				while(dd){
    
    s+=dd%10; dd/=10;}
				int q = (int)sqrt(s);
				if(q*q==s){
    
    
					cnt++;
				}
			}
		}
	}
	cout<<cnt<<"\n";
	return 0;
}


Question 4 - Minimum weight (10 points)

insert image description here

  • The meaning of the question: Given a binary tree, define its weight rules, and find out what the smallest possible weight is.
  • Answer: 2653631372
  • Idea: dp state is the minimum weight value of i nodes. When transferring, enumerate how many nodes there are in the left subtree, and then know the number of nodes in the right subtree, and then know the minimum weight value smaller than the current number of nodes, directly Scan once to get min.
//dp[i]: 有i个节点的树的最小权值
#include<bits/stdc++.h>
using namespace std;
int main(){
    
    
    vector<long long> dp(2022, LLONG_MAX);
    dp[0] = 0;
    for (int i = 1; i <= 2021; i++) {
    
    
        for (int j = 0; j < i; j++) {
    
    
            dp[i] = min(dp[i], 1+2*dp[j]+ 3*dp[i-j-1] + j*j*(i-j-1));
        }
    }
    cout << dp[2021] << endl;
    return 0;
}

Question 5 - Capitalization (15 points)

insert image description here

  • Title: letter case conversion
  • Idea: just output directly
//T5
#include<bits/stdc++.h>
using namespace std;
int main(){
    
    
	string s;  cin>>s;
	for(int i = 0; i < s.size(); i++)
		if(islower(s[i]))s[i] = toupper(s[i]);
	cout<<s;
	return 0;
}


Question 6 - 123 (15 points)

insert image description here
insert image description here

  • Question meaning: Give a regular sequence of numbers, 112123123412345 arranged in this way. T group query, and the sum of the intervals is calculated each time.
  • Idea: The prefix and + violence can exceed 70%.
//baoli 70%
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6+10;

LL num[maxn], ss[maxn];

LL sum(LL x){
    
    
	LL xx = x;
	while(xx>0){
    
    
		LL t = (LL)sqrt(xx*2);
		if(t*(t+1)==xx*2){
    
    
			break;
		}
		xx--;
	}
	
	LL t = sqrt(xx*2);
	LL ans = (1+x-xx)*(x-xx)/2;
	
	ans += ss[t];
	return ans;
}


int main(){
    
    
	for(int i = 1; i < maxn; i++){
    
    
		num[i] = num[i-1]+1;
		ss[i] = ss[i-1]+(1+i)*i/2;
	}
	
	int T;  cin>>T;
	while(T--){
    
    
		LL l, r;  cin>>l>>r;
		cout<<sum(r)-sum(l-1)<<"\n";
	}
	return 0;
}
  • In fact, optimize it again, preprocess the prefix sum, and then add a two-point search to pass it (refer to the official problem solution, I am too lazy to retype the problem)
//二分,100%
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e7;

int cnt = 2, tot = 2;
int sum[N + 100], mid[N + 100], b[N + 100];
void init(){
    
    
    sum[1] = 1;  mid[1] = 1;  b[1] = 1;
    for (int i = 3; i <= 1e12; i += cnt) {
    
    
        sum[tot] =  sum[tot - 1] + cnt;//sum数组存的是 1 2 3 4 5 6这个等差数列的前缀和
        mid[tot] = mid[tot - 1] + sum[tot];//mid数组存的是 1 12 123 1234 12345这个数组的前缀和
        b[tot++] = i;//b数组存的是 1 12 123 1234 12345这个数组的每一组最后一位数的下标
        cnt++;
    }
}

signed main() {
    
    
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    init();
    int T;  cin >> T;
    while (T--) {
    
    
        int l, r;  cin >> l >> r;
        int idxl = lower_bound(b + 1, b + tot + 1, l) - b  ;//二分
        int idxr = lower_bound(b + 1, b + tot + 1, r) - b  ;
        cout << mid[idxr - 1] + sum[idxr - (b[idxr] - r)] - mid[idxl - 1] - sum[idxl - (b[idxl ] - l + 1)] << '\n';
    }
    return 0;
}

  • Or if you find that there is a conclusion formula for this question, you can pass it directly by throwing it in.
//结论,100%
#include<bits/stdc++.h>
using namespace std;
long long sum(long long u){
    
    
    double uh = sqrt(2*u)-0.5;
    long long n = (long long)uh;
    u = u-(n*(n+1))/2;
    return (u*(u+1))/2+(n*(n+1)*(n+2))/6;
}
int main(){
    
    
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T;  cin>>T;
    while(T--){
    
    
        long long l, r;  cin>>l>>r;
        cout<<sum(r)-sum(l-1)<<"\n";
    }
    return 0;
}


Question 7 - XOR transformation (20 points)

insert image description here
insert image description here

  • The meaning of the question: Given a 01 string of length n, find out what the string is after t times of transformation. Each transformation let si=si-1 XOR up si.
  • Idea: Violently punch the watch to find the law, and found that the string transformed to the xth power of 2 will return to the original string , so this number can be subtracted, and the rest can be violently transformed.
//T7
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
string c[1000005];
int main(){
    
    
	LL n, t;  cin>>n>>t;
	string a;  cin>>a;
    LL tt = 1;  
    while (tt < n) tt *= 2;  
    t %= tt;
	for(int k = 1; k <= tt; k++){
    
    
		string b = a;
		for(int i = 1; i < n; i++){
    
    
			b[i] = (a[i-1]-'0')^(a[i]-'0')+'0';
		}
		a = b;
		// cout<<k<<": "<<b<<"\n";
		c[k] = b;
	}
	cout<<c[t]<<"\n";
	return 0;
}

Question 8 - Binary Questions (20 points)

insert image description here

  • The meaning of the question: Find how many numbers in the 1-n binary have exactly K 1s, n<1e18
  • Idea: 1e18 must not be enumerated, so it must be a conclusion question, or related to K. The direct conclusion is found to be a bit difficult, so consider from the perspective of K, the binary related dp.
  • Consider the binary law of all numbers smaller than n: if a certain bit of n is 1
    (1) is a binary number with 0, and all the remaining low bits are taken arbitrarily, it may result in a combination number C(n,k), Bits already at 1 are unchanged.
    (2) The binary number whose bit is 1, recurses to the next bit, but adds 1 to the bit that is already 1.
    Then dfs handles.
//AC,100%
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL num, k;  
vector<LL>vc;

//计算组合数C(n,k)
LL f[70][70];
LL cal(LL n, LL k){
    
    
    if(f[n][k])return f[n][k];
    if(n==k || k==0)return 1;
    if(n<k)return 0;
    return f[n][k]=cal(n-1,k-1)+cal(n-1,k);
}

//solve
LL dfs(int i, int cnt){
    
    
    if(cnt==k)return 1;
    if(i<0 || cnt>k)return 0;
    LL res = 0;
    if(vc[i]){
    
    
        res += cal(i, k-cnt);
        res += dfs(i-1, cnt+1);
    }else{
    
    
        res += dfs(i-1, cnt);
    }
    return res;
}

int main(){
    
    
    cin>>num>>k;
    while(num){
    
    
        vc.push_back(num%2);  num /= 2;
    }
    cout<<dfs(vc.size()-1, 0);
	return 0;
}

  • If you can't write it, you can submit an enumeration violence, 50%
//50%
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(){
    
    
	LL n, k;  cin>>n>>k;
	int cnt = 0;
	for(LL i = 1; i <= n; i++){
    
    
		LL x = i, t = 0;
		while(x){
    
     t+=x&1; x>>=1;}
		if(t==k)cnt++;
	}
	cout<<cnt<<"\n";
	return 0;
}

Problem 9 - Reversing the sequence of parentheses (25 points)

insert image description here

insert image description here

  • Intent of the question: For a sequence of parentheses of length n, operate m times, each time the brackets in the lr interval can be reversed, or find L as the left endpoint, and the longest legal bracket sequence corresponds to R.

  • Consider operation 2:
    a sequence of legal parentheses can be equivalently described as the number of left and right parentheses in the sequence is equal, and in any prefix of the sequence, the number of left parentheses is not less than the number of right parentheses.
    A more acceptable statement is: if the left parenthesis is assigned a value of 1 and the right parenthesis is assigned a value of −1, then the sum of the sequence and the smallest prefix sum are both 0.

  • Consider operation 1:
    Subtract each number twice its own, 1-2=-1, (-1)-(-2)=1, and the effect of inversion can be achieved.

  • Then build a line segment tree and maintain at each node:
    the sum, the smallest prefix sum, the rightmost of all smallest prefixes and corresponding endpoints.

  • When querying, divide into two segments on the line segment tree. If the minimum prefix sum is less than 0, consider going left; otherwise, continue going right. Since the minimum prefix sum of the interval formed by l and the dichotomized endpoint (r') is exactly 0, the answer is the rightmost among all the minimum prefixes and corresponding endpoints of [l,r ′ ].

  • I don’t want to type codes for supplementary questions, so post a code that can pass dalao. refer to

//AC
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
#define mid ((l + r) >> 1)
#define ls (t << 1)
#define rs (t << 1 | 1)
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node{
    
    int mx , mi , sw , add;}tr[maxn << 2];
int a[maxn];
char s[maxn];
int n , m;
template <typename T>
void read(T & x){
    
     x = 0;T f = 1;char ch = getchar();while(!isdigit(ch)){
    
    if(ch == '-') f = -1;
ch = getchar();}while (isdigit(ch)){
    
    x = x * 10 + (ch ^ 48);ch = getchar();}x *= f;}
template <typename T>
void write(T x){
    
    if(x < 0){
    
    putchar('-');x = -x;}if (x > 9)write(x / 10);putchar(x % 10 + '0');}

void pushup (int t){
    
    
    tr[t].mx = max(tr[ls].mx , tr[rs].mx);
    tr[t].mi = min(tr[ls].mi , tr[rs].mi);
}
void build (int t , int l , int r){
    
    
    if (l == r){
    
    
        tr[t].mx = tr[t].mi = a[l];
        return ;
    }
    build(ls , l , mid);
    build(rs , mid + 1 , r);
    pushup(t);
}
void D_sw (int t){
    
    
    int mx = tr[t].mx , mi = tr[t].mi;
    tr[t].mx = -mi; tr[t].mi = -mx;
    tr[t].sw ^= 1;
    tr[t].add *= -1;
}
void D_add (int t , int c){
    
    
    tr[t].mi += c;
    tr[t].mx += c;
    tr[t].add += c;
}
void pushdown (int t){
    
    
    if (tr[t].sw){
    
    
        D_sw(ls);
        D_sw(rs);
        tr[t].sw = 0;
    }
    if (tr[t].add){
    
    
        D_add(ls,tr[t].add);
        D_add(rs,tr[t].add);
        tr[t].add = 0;
    }
}
void Swap (int t , int l , int r , int L , int R){
    
    
    if (L <= l && r <= R){
    
    
        D_sw(t);
        return ;
    }
    pushdown(t);
    if (L <= mid) Swap(ls , l , mid , L , R);
    if (R > mid) Swap(rs , mid + 1 , r , L , R);
    pushup(t);
    return ;
}
void add (int t , int l , int r , int L , int R , int c){
    
    
    if (L <= l && r <= R){
    
    
        D_add(t , c);
        return ;
    }
    pushdown(t);
    if (L <= mid) add(ls , l , mid , L , R , c);
    if (R > mid) add(rs , mid + 1 , r , L , R , c);
    pushup(t);
    return ;
}
// 单点查值
int ask1 (int t , int l , int r , int p){
    
    
    if (l == r) return tr[t].mx;
    pushdown(t);
    if (p <= mid) return ask1(ls , l , mid , p);
    return ask1(rs , mid + 1 , r , p);
}
// 找[p,n]中离p最近的一个小于c的点
int ask2 (int t , int l , int r , int p , int c){
    
    
    // -1 代表该区域没有 < c 的数
    if (l == r) return l;
    pushdown(t);
    // 优先往左走,再考虑什么情况下可以往左走
    // PS:这么走,答案只是"可能"存在
    int res = -1;
    if (tr[ls].mi < c && p <= mid)
        res = ask2(ls , l , mid , p , c);
    if (res != -1) return res;
    // 程序能执行到这里代表左边不存在答案了.只能往右走了
    if (tr[rs].mi < c)
        res = ask2(rs , mid + 1 , r , p , c);
    return res;
}
// 找[1,p]中离p最近的小于c的点
int ask3 (int t , int l , int r , int p , int c){
    
    
    if (l == r) return l;
    pushdown(t);
    int res = -1;
    if (tr[rs].mi < c && p > mid)
        res = ask3(rs , mid + 1 , r , p , c);
    if (res != -1) return res;
    if (tr[ls].mi < c) res = ask3(ls , l , mid , p , c);
    return res;
}
int pre[maxn];
void modify (int x){
    
    
    if (x == 0) return ;
    int v = ask1(1 , 1 , n , x);
    Swap(1 , 1 , n , 1 , x);
    if (x != n) add(1 , 1 , n , x + 1 , n , -2 * v);
}
int main()
{
    
    
    read(n); read(m);
    scanf("%s" , s + 1);
    for (int i = 1 ; i <= n ; i++){
    
    
        if (s[i] == '(') a[i] = a[i - 1] + 1;
        else a[i] = a[i - 1] - 1;
    }
    build(1 , 1 , n);
    for (int i = 1 ; i <= m ; i++){
    
    
        int op , x , y; read(op);
        if (op == 1){
    
    
            read(x);read(y);
            modify(x - 1);
            modify(y);
        }else {
    
    
            read(x);
            int v;
            if (x == 1) v = 0;
            else v = ask1(1 , 1 , n , x - 1);
            int p = ask2(1 , 1 , n , x , v);
            if (p == -1) p = n + 1;
            int r = ask3(1 , 1 , n , p - 1 , v + 1);
            if (r == -1) r = 0;
            printf("%d\n" ,  (r <= x ? 0 : r));
        }
    }
    return 0;
}

Question 10 - XOR Triangle (25 points)

insert image description here
insert image description here

  • The meaning of the question: Given T numbers, for each number x, find out how many triples abc are less than x, and the XOR sum of abc is 0, and abc can form a triangle.
  • The XOR sum is 0, which means that the number of 1s in each of the three numbers can only be 0 or 2.
  • Suppose n>a>b>c, then for each bit, the state of the bit of abc being 110 should appear before 101.
  • Considering that a triangle can be formed, that is, a<b+c, and XOR is 0 to get a=b^c, so b^c<b+c, so there must be a set of 011 states.
  • Enumerate ac to ensure that the above constraints are met before outputting, refer to
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, f[40][2][2][2][2];
LL dfs(LL a, LL c, LL i, LL j, LL k){
    
    
    if(i==-1)return k;
    if(f[i][j][k][c][a] != -1)return f[i][j][k][c][a];
    LL top = j ? ((n>>i)&1) : 1 ;
    LL res = 0;
    for(LL bt = 0; bt <= top; bt++){
    
    
        LL nj = (j&&(bt==top));
        if(bt){
    
    
            if(!a)res += dfs(1,c,i-1,nj,k); //a最大,最高位1给a和b 
            else{
    
    
                res += dfs(1,c,i-1,nj,k); //给a、b 
				res += dfs(1,1,i-1,nj,k); //给a、c 
            }
        }else{
    
    
            res += dfs(a,c,i-1,nj,k);        //全0 
			if(c!=0) res+=dfs(a,1,i-1,nj,1); //给b、c,若c==0,给b、c的话会使b>a  
        }
    }
    return f[i][j][k][c][a]=res;
}
int main(){
    
    
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T;  cin>>T;
    while(T--){
    
    
        cin>>n;
        memset(f,-1,sizeof f);
        cout<<dfs(0,0,31,1,0)*6LL<<"\n";
    }
    return 0;
}


Guess you like

Origin blog.csdn.net/qq_33957603/article/details/130496703