2023年十四届蓝桥杯国赛(JavaB组)

本文介绍了2023年蓝桥杯国赛JavaB组的几道算法题目,包括互质问题、逆元计算、玩具排序、不完整的等式、星球问题、序列分析、电动车路径规划和非对称二叉树。题目涉及了数论、动态规划、贪心策略、模拟计算、旅行商问题、最小生成树、线段树和二叉树等相关算法知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在这里插入图片描述
2023.6.16: 出成绩了,国一第15前排靠后,算是完成任务

先简单写写,数据范围可能有小错,等题面出来了再更新

2024.6.1:已更新体面,更新 I 题题解


A: 互质

本题总分:5分


【问题描述】

求出在 [ 1 , 202 3 2023 ] [1,2023^{2023}] [1,20232023]范围内,有多少个整数与 2023 2023 2023 互质,答案对 1 0 9 + 7 10^9+7 109+7取模。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


640720414


md考试时脑抽把 1 1 1 给减掉了,白白丢了 5 5 5 分。。
易得 2023 = 7 ∗ 17 ∗ 17 2023=7*17*17 2023=71717,故可以先求出与2023不互质的数,然后总数减去即可。
a a a 为因数有7的数, b b b 为因数有17的数, c c c 为因数有7*17=119的数,显然不互质的数的总量为: a + b − c a+b-c a+bc.

	static long fpow(long a,long b) {
    	long res = 1;
    	a%=mod;
    	while(b>0) {
    		if(b%2==1) res = res*a%mod;
    		a = a*a%mod;
    		b/=2;
    	}
    	return res;
    }
    
    static void solve() throws IOException{
    	long res=fpow(2023,2023);
    	long a = fpow(2023,2023)*fpow(7,mod-2)%mod;
    	long b = fpow(2023,2023)*fpow(17,mod-2)%mod;
    	long c = fpow(2023,2023)*fpow(7*17,mod-2)%mod;
    	res = (res-a-b +c+2*mod)%mod;
    	pw.println(res);
    	
	}

B: 逆元

本题总分:5分


【问题描述】

给定质数 M = 2146516019 M=2146516019 M=2146516019, 求出在 [ 1 , 233333333 ] [1,233333333] [1,233333333]内所有自然数的逆元。则所有逆元的异或和为多少?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


1307261675


快速幂暴力求逆元,逐个异或,比赛时跑了大概10多分钟

	static long fpow(long a,long b) {
		long res = 1;
    	a%=mod;
    	while(b>0) {
    		if(b%2==1) res = res*a%mod;
    		a = a*a%mod;
    		b/=2;
    	}
    	return res;
	}
	
    
	static void solve() throws IOException{
		mod = 2146516019;
		ans=0;
		for(int i=1;i<=233333333;i++) {
			long res = fpow(i,mod-2);
			ans ^=res;
		}
		System.out.println(ans);
	}

线性求逆元

对于求解 1 , 2 , 3 , . . . , n 1,2,3,...,n 1,2,3,...,n 每个数的逆元,用快速幂或扩展欧几里得就很慢,有一种线性求逆元的方法:

这里给出递推式:
i − 1 = { 1 , i = 1 − ⌊ p i ⌋ ( p   m o d   i ) − 1 , i ≠ 1 ( m o d   p ) i^{-1}= \begin{cases} 1, & i=1\\ -\lfloor {p \over i} \rfloor(p \space mod \space i)^{-1}, & i \not =1 \end{cases} (mod \space p) i1={1,ip(p mod i)1,i=1i=1(mod p)
推导:

显然 1 − 1 ≡ 1   ( m o d   p ) 1^{-1} \equiv 1 \space (mod \space p) 111 (mod p)
对于 i − 1 i^{-1} i1,令 k = ⌊ p i ⌋ k=\lfloor {p \over i} \rfloor k=ip j = p   m o d   i j=p \space mod \space i j=p mod i,有 p = k i + j p=ki+j p=ki+j,即 k i + j ≡ 0   ( m o d   p ) ki+j \equiv 0 \space(mod \space p) ki+j0 (mod p)
两边同乘以 i − 1 × j − 1 i^{-1} \times j^{-1} i1×j1,化简得到 i − 1 ≡ − k j − 1   ( m o d   p ) i^{-1} \equiv -kj^{-1} \, (mod\,p) i1kj1(modp)
带入 j = p   m o d   i j=p \space mod \space i j=p mod i,又 p = k i + j p=ki+j p=ki+j,有:
i − 1 ≡ − ⌊ p i ⌋ ( p   m o d   i ) − 1   ( m o d   p ) i^{-1} \equiv -\lfloor {p\over i}\rfloor (p\space mod\space i)^{-1}\space (mod\space p) i1ip(p mod i)1 (mod p)
p   m o d   i < i p\space mod \space i<i p mod i<i,故可以迭代推出。


	static void solve() throws IOException{
    	mod = 2146516019;
    	long inv[] = new long[233333335];
    	inv[1]=1;
    	ans=1;
    	for(int i=2;i<=233333333;i++) {
    		inv[i] = (long)(mod-mod/i)*inv[(int)(mod%i)]%mod;
    		ans ^=inv[i];
    	}
    	pw.println(ans);
	}

C: 玩具

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 10 10 10


【问题描述】

小明的妈妈给她买了 n n n 个玩具,但是为了同时考察他的智力,只给了他 2 ∗ n 2*n 2n 个玩具零件,第 i i i 个零件的重量为 w i ( 1 ≤ i ≤ 2 ∗ n ) w_i(1≤i≤2*n) wi1i2n

其中任意两个零件都能拼接成一个玩具,这个玩具的权重等于这两个零件的重量的乘积。小明的妈妈希望小明能够使用这 2 ∗ n 2*n 2n 个零件拼接出 n n n 个玩具(每个零件必须使用且只能使用一次),使得所有玩具的权重的和最小。

小明希望你帮帮他计算出最小的权重和。

【输入格式】
第一行一个整数 n n n
第二行包含 2 n 2n 2n 个由空格隔开的整数 w 1 , w 2 , . . . , w 2 n w_1,w_2,...,w_{2n} w1,w2,...,w2n

【输出格式】

一行整数,表示答案。

【样例输入】

2
2 2 3 4

【样例输出】

14

【提示】

对于 20% 的数据, n ≤ 1 0 3 n≤10^3 n103
对于 100% 的数据, 1 ≤ n ≤ 1 0 5 , 0 ≤ w i ≤ 1 0 5 1 ≤ n ≤ 10^5 , 0 ≤ w_i ≤ 10^5 1n105,0wi105


贪心

排序,取最大和最小的乘积贡献到答案中即可。
这不沙比题么

import java.util.*;
import java.io.*;
public class Main {
	static int n,m,mod=(int)998244353,maxn=200005,inf=(int)1e9;
	static long ans=0,INF=(long)1e18;
	public static void main(String[]args) throws IOException{
		int T = 1;
		while(T-->0) solve();
	}
	
  	static Scanner sc = new Scanner (System.in);
	static void solve() throws IOException{
		n = sc.nextInt();
		long a[] = new long[maxn];
		for(int i=1;i<=n*2;i++) a[i] = sc.nextLong();
		Arrays.sort(a,1,2*n+1);
		for(int i=1,j=2*n;i<j;i++,j--) {
			ans += a[i]*a[j];
		}
		System.out.println(ans);
	}
}


D: 不完整的等式

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 10 10 10


【问题描述】
给一个等式 A A A o p op op B = C B=C B=C,其中 a , b , c a,b,c a,b,c都是非负整数, o p op op { + , − , ∗ , / } \{+,-,*,/\} {+,,,/} 四个中的一个。 a , b , c , o p a,b,c,op a,b,c,op 四个中一个会被 ? ? ? 代替,输出被代替的那个数或符号,保证有唯一解。

【输入格式】

输入一行字符串表示不完整的等式。

【输出格式】

输出被代替的那个数或符号。

【样例输入1】

1+?=2

【样例输出1】

1

【样例输入2】

10?3=3

【样例输出2】

/

【提示】
对于 20% 的数据,被擦掉的部分是 C C C
对于 40% 的数据,被擦掉的数据是 o p op op
对于 100% 的数据,算式长度不超过10,不包含空格。算式中出现的整数不包含前导零。输入保证合法且有唯一解。


模拟,没什么好说的

import java.util.*;
import java.io.*;
public class Main {
    static int n,m,mod=(int)998244353,maxn=200005,inf=(int)1e9;
    static long ans=0,INF=(long)1e18;
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(bf);
    static PrintWriter pw = new PrintWriter(System.out);
    public static void main(String[]args) throws IOException{
        int T = 1;
        //T = Integer.parseInt(S());
        while(T-->0) solve();
        pw.flush();
    }
    
    static int I() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    static long c1(long a,long b,char op) {
        if(op=='+') return a+b;
        if(op=='-') return a-b;
        if(op=='*') return a*b;
        return a/b;
    }
    
    static long c2(long a,long b,char op) {
        if(op=='+') return a-b;
        if(op=='-') return a+b;
        if(op=='*') return a/b;
        return b*a;
    }

    static long c3(long a,long b,char op) {
        if(op=='+') return a-b;
        if(op=='-') return a+b;
        if(op=='*') return a/b;
        return b/a;
    }

  static Scanner sc = new Scanner(System.in);
    
    static void solve() throws IOException{
        String s[] = sc.next().split("=");
        if(s[1].equals("?")) {
            long a=0,b=0;
            char op = ' ';
            int i=0;
            for(;i<s[0].length();i++) {
                char c = s[0].charAt(i);
                if(c<'0' || c>'9') break;
                a = a*10+(int)(c-'0');
            }
            op = s[0].charAt(i++);
            for(;i<s[0].length();i++) {
                char c = s[0].charAt(i);
                b = b*10+(int)(c-'0');
            }
            pw.println(c1(a,b,op));
        }
        else {
            if(s[0].charAt(0)=='?') {
                long a=Long.parseLong(s[1]),b=0;
                char op = ' ';
                int i=1;
                op = s[0].charAt(i++);
                for(;i<s[0].length();i++) {
                    char c = s[0].charAt(i);
                    b = b*10+(int)(c-'0');
                }
                pw.println(c2(b,a,op));
            }
            else {
                long a=0,b=0;
                char op = ' ';
                int i=0;
                for(;i<s[0].length();i++) {
                    char c = s[0].charAt(i);
                    if(c<'0' || c>'9') break;
                    a = a*10+(int)(c-'0');
                }
                op = s[0].charAt(i++);
                if(op=='?') {
                    for(;i<s[0].length();i++) {
                        char c = s[0].charAt(i);
                        b = b*10+(int)(c-'0');
                    }
                    long c = Long.parseLong(s[1]);
                    if(a+b==c) pw.println("+");
                    if(a*b==c) pw.println("*");
                    if(a/b==c) pw.println("/");
                    if(a-b==c) pw.println("-");
                }
                else {
                    b=Long.parseLong(s[1]);
                    pw.println(c3(b,a,op));
                }
            }
        }
    }
}



E: 星球

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 15 15 15


【问题描述】

小明驾驶飞船对某星系发起攻击。星系中有 n n n 颗星球,编号依次是 1,2,3,…, n n n 。第 i i i 颗星球的坐标是 ( x i , y i , z i x_i,y_i,z_i xi,yi,zi),且其防御强度为 w i w_i wi

小明需要规划出进攻这 n n n 颗星球的顺序使得其进攻所需能量最少。

对于一个遍历顺序 { p 1 , p 2 , . . . , p n } \{p_1,p_2,...,p_n\} {p1,p2,...,pn},小明进攻所需的能量为 E = ∑ i = 2 n d ( p i − 1 , p i ) ∗ w i E=\sum_{i=2}^n d(p_{i-1},p_i)*w_i E=i=2nd(pi1,pi)wi,其中 d ( p i − 1 , p i ) d(p_{i-1},p_i) d(pi1,pi) 表示 p i − 1 , p i p_{i-1},p_i pi1,pi 两颗星球之间的直线距离。小明想知道进攻所需的最少能量是多少。

【输入格式】

1 1 1 行一个整数 n n n
后面 n n n 行,每行给出四个整数 x i , y i , z i , w i x_i,y_i,z_i,w_i xi,yi,zi,wi

【输出格式】

一个浮点数,保留两位有效数字。

【样例输入】

3
4 3 3 5
2 2 3 5
3 1 1 3

【样例输出】

18.53

【提示】

对于 20% 的评测用例, N ≤ 8 N ≤ 8 N8
对于 100% 的评测用例, N ≤ 18 , 0 ≤ x i , y i , z i , w i < = 100 N ≤ 18 , 0≤x_i,y_i,z_i,w_i<=100 N18,0xi,yi,zi,wi<=100


状压dp

旅行商问题变种。不了解的可以自行查询学习

在原旅行商问题中,有 n n n 个点。若起始点为 0 0 0,设 d p [ i ] [ S ] dp[i][S] dp[i][S] 为从点 i i i 出发,经过点的集合为 S S S且都只经过一次,最终返回出发点 0 0 0 的最小花费。显然总集合数量为 2 n 2^n 2n 种。
这题可以虚设一个点 0 0 0 ,设点 0 0 0 到任何点距离都为 0 0 0,那么显然最终答案为 d p [ 0 ] [ 2 n − 1 ] dp[0][2^n-1] dp[0][2n1].

时间复杂度: O ( n 2 ∗ 2 n ) O(n^2*2^{n}) O(n22n)

import java.io.*;
import java.util.*;
public class Main{
    static int maxn = 200005,n,m,inf=(int)2e9;
    static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
    static Scanner sc = new Scanner (System.in);
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st  =new StreamTokenizer(bf);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[]args) throws IOException{
        int T = 1;
        while(T-->0) solve();
        pw.flush();
    }
    static final int I() throws IOException {
        st.nextToken();
        return (int)st.nval;
    }
    
    static long[]w=new long[20];
    static int []x = new int [20],y=new int [20],z=new int[20];
    static double as=INF;
    static double dis(int i,int j) {
        if(i==0) return 0;
        return Math.sqrt(Math.pow(x[i]-x[j], 2)+Math.pow(y[i]-y[j], 2)+Math.pow(z[i]-z[j], 2))*w[j];
    }
    
    static void solve() throws IOException{
        n = I();
        for(int i=1;i<=n;i++) {
            x[i]=I();y[i]=I();z[i]=I();w[i] = I();
        }
        m = 1<<n; //集合数量
        double dp[][] = new double[22][m];
        for(int j=1;j<m;j++) {
            for(int i=0;i<=n;i++) {
                dp[i][j] = INF;
                if((j>>(i-1))%2==1) continue; //集合有 i,跳过
                for(int k=1;k<=n;k++) {
                    if((j>>(k-1))%2==0) continue;
                    if(dp[i][j] > dis(i,k) + dp[k][j^(1<<(k-1))])
                        dp[i][j] = dis(i,k) + dp[k][j^(1<<(k-1))];
                }
            }
        }
        pw.printf("%.2f",dp[0][m-1]);
    }
}

F: 序列

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 15 15 15


【问题描述】

给定一长为 n n n 的正整数序列 A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An,同时有一个首项为 d d d,公差为 d d d,项数为 n n n 的等差数列 { b 1 = d , b 2 = 2 d , . . . , b n = n d } \{b_1=d,b_2=2d,...,b_n=nd\} {b1=d,b2=2d,...,bn=nd}

定义 S d = ∑ a i ∣ b i 1 S_d=\sum_{a_i|b_i}1 Sd=aibi1,即 S d S_d Sd 表示当公差为 d d d 时有多少对 ( a i , b i ) (a_i,b_i) (ai,bi) 满足 b i b_i bi a i a_i ai 整除。

请求出 ∑ i = 1 n S i \sum_{i=1}^nS_i i=1nSi

【输入格式】

第一行一个整数 n n n;
第二行 n n n 个整数 A 1 , A 2 , . . , A n A_1,A_2,..,A_n A1,A2,..,An

【输出格式】

一行整数,表示答案。

【样例输入】

4
2 2 3 1

【样例输出】

14

【样例说明】
当公差等于 1 1 1 b = { 1 , 2 , 3 , 4 } b=\{1,2,3,4\} b={1,2,3,4} S 1 = 3 S_1=3 S1=3
当公差等于 2 2 2 b = { 2 , 4 , 6 , 8 } b=\{2,4,6,8\} b={2,4,6,8} S 2 = 4 S_2=4 S2=4
当公差等于 3 3 3 b = { 3 , 6 , 9 , 12 } b=\{3,6,9,12\} b={3,6,9,12} S 3 = 3 S_3=3 S3=3
当公差等于 4 4 4 b = { 4 , 8 , 12 , 16 } b=\{4,8,12,16\} b={4,8,12,16} S 4 = 4 S_4=4 S4=4
所以答案为 3 + 4 + 3 + 4 = 14 3+4+3+4=14 3+4+3+4=14

【提示】
对于 100% 的数据, n ≤ 1 0 3 n≤10^3 n103
对于 100% 的数据, 1 ≤ n ≤ 1 0 5 , 1 ≤ A i ≤ n 1 ≤ n ≤ 10^5 , 1 ≤ A_i ≤ n 1n105,1Ain


考虑单独处理每个数。
x = d ∗ i x=d*i x=di,显然 m i n ( x ) = l c m ( A i , i ) min(x)=lcm(A_i,i) min(x)=lcm(Ai,i) ,则对答案的贡献为 i ∗ n / m i n ( x ) i*n/min(x) in/min(x)

import java.io.*;
import java.util.*;
public class Main{
    static int maxn = 200005,n,m,inf=(int)2e9;
    static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
    static Scanner sc = new Scanner (System.in);
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st  =new StreamTokenizer(bf);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[]args) throws IOException{
        int T = 1;
        //T = I();
        while(T-->0) solve();
        pw.flush();
    }
    static final int I() throws IOException {
        st.nextToken();
        return (int)st.nval;
    }
    
    static int gcd(int a,int b) {
    	if(b==0) return a;
    	return gcd(b,a%b);
    }
    
    static long lcm(int a,int b) {
    	return 1L*a*b/gcd(a,b);
    }
    
    static void solve() throws IOException{
    	n = I();
    	for(int i=1;i<=n;i++) {
    		int a=I();
    		long x = lcm(a,i);
    		ans += (1L*n*i)/x;
    	}
    	pw.println(ans);
	}
}



G: 电动车

时间限制: 1.0 s 1.0 s 1.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 20 20 20


【问题描述】

n n n 个城市,由 m m m 条双向高速公路相连。其中第 i i i 条高速公路连接 u i u_i ui 号城市和 v i v_i vi 号城市,耗费 w i w_i wi 个单位的电量。

假设小蓝可以在出发城市,以及任何中途经过的城市里充满电。小蓝想知道,如何希望从任意城市开电动车到任意另一个城市,都可以找到一条由若干高速公路组成路径,使得不需要在任何高速公路内补充电量,那么这台电动车至少需要多少电量?

【输入格式】

1 1 1 行两个整数 N , M N,M N,M
2 2 2 m + 1 m+1 m+1 行,每行三个整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi

【输出格式】

一行一个整数,表示答案。
如果存在两个城市不能相互到达,输出 − 1 -1 1

【样例输入】

4 5
1 2 3
1 3 5
2 4 2
4 3 2
4 1 4

【样例输出】

3

【样例说明】

1 1 1 2 2 2 可以走: 1 → 2 1 \rightarrow 2 12,至少需要电量 3 3 3
1 1 1 3 3 3 可以走: 1 → 2 → 4 → 3 1 \rightarrow 2 \rightarrow 4 \rightarrow 3 1243,至少需要电量 3 3 3
1 1 1 4 4 4 可以走: 1 → 2 → 4 1 \rightarrow 2 \rightarrow 4 124,至少需要电量 3 3 3
2 2 2 3 3 3 可以走: 2 → 4 → 3 2 \rightarrow 4 \rightarrow 3 243,至少需要电量 2 2 2
2 2 2 4 4 4 可以走: 2 → 4 2 \rightarrow 4 24,至少需要电量 2 2 2
3 3 3 4 4 4 可以走: 3 → 4 3 \rightarrow 4 34,至少需要电量 2 2 2

综上所述,电动车至少需要 3 3 3 个单位的电量。

【提示】
对于 20% 的数据, 1 ≤ N , M ≤ 100 , 0 ≤ w i ≤ 100 1 ≤ N,M ≤ 100, 0 ≤ w_i ≤ 100 1N,M100,0wi100
对于 100% 的数据, 1 ≤ N , M ≤ 2 ∗ 1 0 5 , , 0 ≤ w i ≤ 1 0 9 1 ≤ N,M ≤ 2*10^5 ,, 0 ≤ w_i ≤ 10^9 1N,M2105,,0wi109


最小生成树

板子题。

import java.io.*;
import java.util.*;
public class Main{
    static int maxn = 200005,n,m,inf=(int)2e9;
    static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
    static Scanner sc = new Scanner (System.in);
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st  =new StreamTokenizer(bf);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[]args) throws IOException{
        int T = 1;
        while(T-->0) solve();
        pw.flush();
    }
    static final int I() throws IOException {
        st.nextToken();
        return (int)st.nval;
    }
    
    static class edge{
    	int u,v,w;
    	public edge(int a,int b,int c) {
    		u=a;v=b;w=c;
    	}
    }
    
    static int p[] = new int [maxn];
    static int find(int x) {
    	if(p[x] == x) return x;
    	return p[x] = find(p[x]);
    }
    
    static Vector<edge> g = new Vector<>();
    static void krus() {
    	Collections.sort(g,(o1,o2)->o1.w-o2.w);
    	int cnt=0;
    	for(edge x:g) {
    		int a=x.u,b=x.v,w=x.w;
    		int aa = find(a),bb = find(b);
    		if(aa!=bb) {
    			p[aa]=bb;
    			ans=w;
    			cnt++;
    		}
    	}
    	if(cnt!=n-1) pw.println(-1); //不连通
    	else pw.println(ans);
    }
    
    static void solve() throws IOException{
    	n = I();m=I();
      for(int i=1;i<=n;i++) p[i] = i;
    	while(m-->0) {
    		g.add(new edge(I(),I(),I()));
    	}
    	krus();
	}
}


H: 游戏

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 20 20 20


【问题描述】

给定一个长度为 n n n 的数组 [ a 1 , a 2 , . . . , a n ] [a_1,a_2,...,a_n] [a1,a2,...,an],熊大均匀随机选取连续的一段长度为 k k k 的序列,取序列最大值为 P P P;熊二均匀随机选取连续一段长度为 k k k 的序列,取序列最小值为 Q Q Q

P − Q P-Q PQ 的期望值。

【输入格式】

第一行两个整数 n n n k k k;
第二行 n n n 个整数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an;

【输出格式】

一个浮点数,表示期望,保留两位有效数字。

【样例输入】

3 2
1 2 3

【样例输出】

1.00

【样例说明】
一共四种情况:
熊大选 [ 1 , 2 ] [1,2] [1,2] P = 2 P=2 P=2;熊二选 [ 1 , 2 ] [1,2] [1,2] Q = 1 Q=1 Q=1 P − Q = 1 P-Q=1 PQ=1
熊大选 [ 1 , 2 ] [1,2] [1,2] P = 2 P=2 P=2;熊二选 [ 2 , 3 ] [2,3] [2,3] Q = 2 Q=2 Q=2 P − Q = 0 P-Q=0 PQ=0
熊大选 [ 2 , 3 ] [2,3] [2,3] P = 3 P=3 P=3;熊二选 [ 1 , 2 ] [1,2] [1,2] Q = 1 Q=1 Q=1 P − Q = 2 P-Q=2 PQ=2
熊大选 [ 2 , 3 ] [2,3] [2,3] P = 2 P=2 P=2;熊二选 [ 2 , 3 ] [2,3] [2,3] Q = 1 Q=1 Q=1 P − Q = 1 P-Q=1 PQ=1
所以答案为 ( 1 + 0 + 2 + 1 ) / 4 = 1.00 (1+0+2+1)/4=1.00 (1+0+2+1)/4=1.00

【提示】

对于 100% 的数据, 1 ≤ n ≤ 1 0 5 , 0 < a i ≤ 1 0 9 , 0 < k ≤ n 1 ≤ n ≤ 10^5,0<a_i≤10^9,0<k≤n 1n1050<ai1090<kn


线段树 or 单调队列

区间维护最大最小,线段树应该大概不会超时,(主要是单调队列求最值忘了

手玩一下,答案可以写成 A n s = c n t ∗ ( ∑ P − ∑ Q ) / ( c n t ∗ c n t ) = ( ∑ P − ∑ Q ) / c n t Ans={cnt*(\sum P - \sum Q) / (cnt*cnt)}=(\sum P - \sum Q)/cnt Ans=cnt(PQ)/(cntcnt)=(PQ)/cnt。其中 c n t = n − k + 1 cnt=n-k+1 cnt=nk+1 表示可以选择多少个不同区间, ∑ P \sum P P 所有不同区间的最大值之和, ∑ Q \sum Q Q 所有不同区间的最小值之和,那么答案显然。

P . S . P.S. P.S. 题面出来发现是 n ≤ 1 0 5 n≤10^5 n105,那线段树应该挺快,要是 n ≤ 2 ∗ 1 0 6 n≤2*10^6 n2106 稳妥起见还是写单调队列吧。。

import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
    static int maxn = 2000005,n,m,inf=(int)2e9;
    static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
    static Scanner sc = new Scanner (System.in);
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st  =new StreamTokenizer(bf);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[]args) throws IOException{
        int T = 1;
        //T = I();
        while(T-->0) solve();
        pw.flush();
    }
    static final int I() throws IOException {
        st.nextToken();
        return (int)st.nval;
    }
    
    static int a[] = new int [maxn];
    static int mi[] = new int [maxn<<2];
    static int mx[] = new int [maxn<<2];
    static void up(int i) {
    	mi[i] = Math.min(mi[i<<1], mi[i<<1|1]);
    	mx[i] = Math.max(mx[i<<1], mx[i<<1|1]);
    }
    
    static void build(int i,int l,int r) {
    	if(l==r) {
    		mx[i]=mi[i]=a[l];return;
    	}
    	int mid=(l+r)/2;
    	build(i<<1,l,mid);build(i<<1|1,mid+1,r);
    	up(i);
    }
    
    static int query_mi(int i,int l,int r,int ll,int rr) {
    	if(ll<=l && r<=rr) return mi[i];
    	int mid=(l+r)/2;
    	int res = inf;
    	if(mid >=ll) res = Math.min(res, query_mi(i<<1,l,mid,ll,rr));
    	if(mid+1 <= rr) res = Math.min(res, query_mi(i<<1|1,mid+1,r,ll,rr));
    	return res;
    }
    
    static int query_mx(int i,int l,int r,int ll,int rr) {
    	if(ll<=l && r<=rr) return mx[i];
    	int mid=(l+r)/2;
    	int res = 0;
    	if(mid >=ll) res = Math.max(res, query_mx(i<<1,l,mid,ll,rr));
    	if(mid+1 <= rr) res = Math.max(res, query_mx(i<<1|1,mid+1,r,ll,rr));
    	return res;
    }
    
    
    static void solve() throws IOException{
    	n = I();m=I();
    	for(int i=1;i<=n;i++) {
    		a[i]=I();
    	}
    	build(1,1,n);
    	long cnt=n-m+1;
    	double ans=0;
    	for(int i=1;i+m-1<=n;i++) {
    		int j = i+m-1;
    		ans += query_mx(1,1,n,i,j) - query_mi(1,1,n,i,j);
    	}
    	pw.printf("%.2f\n",ans/cnt);
	}
}

I: 非对称二叉树

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 25 25 25


【问题描述】

小明觉得不对称的东西有独特的美感。

对于一颗含有 n n n 个结点的二叉树,小明规定如果对于其中任意一个结点 i i i 都满足条件: m a x { h l i , h r i } ⩾ k ∗ m i n { h l i , h r i } max\{h_{l_i},h_{r_i}\}\geqslant k*min\{h_{l_i},h_{r_i}\} max{hli,hri}kmin{hli,hri},则此二叉树为一颗非对称二叉树。其中 l i , r i l_i,r_i li,ri 分别是 i i i 的左儿子和右儿子, h x h_x hx 表示以 x x x 为根的子树高度(如果结点 x x x 不存在视为高度等于 0 0 0)。

给定 n , k n,k n,k,计算有多少种非对称二叉树。

【输入格式】

输入共一行,两个整数 n , k n,k n,k

【输出格式】

一行整数,表示答案。

【样例输入】

4 2

【样例输出】

12

【提示】

对于 20% 的数据, n ≤ 12 n≤12 n12
对于 100% 的数据, n ≤ 35 , 1 ≤ k ≤ n n ≤ 35 , 1 ≤ k ≤ n n35,1kn


动态规划

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示含有 n n n 个结点且高度为 j j j 非对称二叉树数量。

有转移式: d p [ i ] [ m a x { h l i , h r i } + 1 ] = ∑ m a x { h l i , h r i } ⩾ k ∗ m i n { h l i , h r i } d p [ l c n t ] [ h l i ] ∗ d p [ r c n t ] [ h r i ] dp[i][max\{h_{l_i},h_{r_i}\}+1]=\sum_{max\{h_{l_i},h_{r_i}\}\geqslant k*min\{h_{l_i},h_{r_i}\}}dp[l_{cnt}][h_{l_i}]*dp[r_{cnt}][h_{r_i}] dp[i][max{hli,hri}+1]=max{hli,hri}kmin{hli,hri}dp[lcnt][hli]dp[rcnt][hri]
其中, l c n t , r c n t l_{cnt},r_{cnt} lcnt,rcnt 表示左、右子树的结点数量。

枚举 i , l c n t i,l_{cnt} i,lcnt,即可得到 r c n t r_{cnt} rcnt,再枚举 h l i , h r i h_{l_i},h_{r_i} hli,hri 即可转移。

复杂度: O ( n 4 ) O(n^4) O(n4)

import java.util.*;
import java.io.*;
import java.math.*;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in),65535);
	static StreamTokenizer st = new StreamTokenizer(bf);
	static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
	static int n,m,maxn=200005,inf = 0x3f3f3f3f;
	static long ans=0,mod=(int)1e9+7,INF=(long)2e18;
	public static void main(String[]args) throws IOException{
		new Task().main();
		pw.flush();
	}
	static int I() throws IOException {
		st.nextToken();
		return (int)st.nval;
	}
	static class Task{
		void main()throws IOException{
			int t=1;
			//t=I();
			while(t-->0) solve();
		}
		
		long [][]dp = new long[44][44];
		
		private void solve() throws IOException {
			n=I();m=I();
			dp[1][1]=1;
			dp[0][0]=1;
			for(int i=2;i<=n;i++) {
				for(int j=0;j<i;j++) {
					int k=i-j-1;
					for(int h1=0;h1<=j;h1++) {
						for(int h2=0;h2<=k;h2++) {
							int mx = Math.max(h1, h2),mi = Math.min(h1, h2);
							if(mx < 1L*m*mi) continue;
							dp[i][mx+1] += dp[j][h1]*dp[k][h2];
						}
					}
				}
			}
			for(int i=1;i<=n;i++) ans += dp[n][i];
			pw.println(ans);
		}
	}
}

J: 数和游戏

时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 25 25 25


没思路,有时间再看吧


以上。

### 关于第十四届蓝桥杯 Java B的信息 #### 考试内容概述 蓝桥杯作为一项面向全高校学生的科技竞活动,其目标在于培养大学生的创新思维和实践能力。对于Java B而言,主要考察选手的基础算法设计能力和程序实现技巧[^1]。具体来说,比通常涉及以下几个方面: - **基础语法**:包括但不限于变量定义、数据类型转换以及条件判断语句等基本概念。 - **控制结构**:重点测试各种循环(for, while)的应用场景及其嵌套逻辑处理方式。 - **数操作**:如何高效地初始化、遍历并修改多维数中的元素成为常见考点之一。 - **字符串处理**:掌握正则表达式匹配模式查找特定子串或者完成简单文本替换功能显得尤为重要。 #### 题目解析示例 以下是基于以往经验总结出来的一类典型问题——寻找质数列表,并附带相应解决方案说明: 假设我们需要编写一段代码来找出小于等于N的所有素数,则可以采用如下方法实现: ```java public class PrimeNumbers { public static void main(String[] args){ int N = 50; boolean[] isPrime=new boolean[N+1]; Arrays.fill(isPrime,true); isPrime[0]=false; isPrime[1]=false; for(int i=2;i*i<=N;i++){ if(!isPrime[i]) continue; for(int j=i*2;j<=N;j+=i){ isPrime[j]=false; } } System.out.println("Primes up to "+N+":"); for(int k=0;k<isPrime.length;k++)if(isPrime[k])System.out.print(k+" "); } } ``` 上述代码片段通过埃拉托斯特尼筛法有效减少了不必要的计算量从而提高了执行效率。 #### 备考建议与资源推荐 为了更好地准备此类事,考生可以从以下几方面着手努力: - 加强理论知识积累的同时注重实际动手练习频率; - 积极参与在线评测平台上的模拟训练营项目以检验自身水平差距所在; - 定期复习历真题集锦以便熟悉命题风格特点及解题套路规律; 此外还可以参考一些权威教材如《算法导论》第三版中文翻译版本或是参加由官方授权机构举办的线下辅导班课程进一步提升综合竞争力。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值