2023年第十四届蓝桥杯省赛JavaB组个人题解(AK)

2023-11-02 21:50

本文主要是介绍2023年第十四届蓝桥杯省赛JavaB组个人题解(AK),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2023年第十四届蓝桥杯省赛JavaB组个人题解(AK)

  • A: 阶乘求和
  • B: 幸运数字
  • C: 数组分割
  • D: 矩形总面积
  • E: 蜗牛
  • F: 合并区域
  • G: 买二赠一
  • H: 合并石子
  • I: 最大开支
  • J: 魔法阵


之前在dotcpp上发了几个单独题解,现在补一篇完整的吧
P.S. 当天比完,一回去被室友感染甲流发烧躺了一周,。。(喜
今年相较去年,难度有提升(特别是C++),签到题不怎么签到了。脱离捞钱杯?

2023.4.27:更新 H、J;
2023.4.28:更新 F 正确题解;


A: 阶乘求和

本题总分:5分


【问题描述】

S = 1 ! + 2 ! + 3 ! + . . . + 202320232023 ! S = 1! + 2! + 3! + ... + 202320232023! S=1!+2!+3!+...+202320232023!,求 S S S 的末尾 9 位数字。 提示:答案首位不为 0。

【答案提交】

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


420940313


大于 39 39 39后的阶乘都大于 1 e 9 1e9 1e9,遍历即可

    static void solve() {ans=1;long res=1;for(int i=2;i<=39;i++) {res=res*i%(long)1e9;ans =ans+ res;ans%=(long)1e9;System.out.println(ans);}}

B: 幸运数字

本题总分:5分


【问题描述】

哈沙德数是指在某个固定的进位制当中,可以被各位数字之和整除的正整 数。例如 126 126 126 是十进制下的一个哈沙德数,因为 ( 126 ) 10 m o d ( 1 + 2 + 6 ) = 0 (126)_{10} mod (1+2+6) = 0 (126)10mod(1+2+6)=0 126 126 126 也是八进制下的哈沙德数,因为 ( 126 ) 10 = ( 176 ) 8 , ( 126 ) 10 m o d ( 1 + 7 + 6 ) = 0 (126)_{10} = (176)_8,(126)_{10} mod (1 + 7 + 6) = 0 (126)10=(176)8(126)10mod(1+7+6)=0; 同时 126 126 126 也是 16 16 16 进制下的哈沙德数,因为 ( 126 ) 10 = ( 7 e ) 16 , ( 126 ) 10 m o d ( 7 + e ) = 0 (126)_{10} = (7e)_{16},(126)_{10} mod (7 + e) = 0 (126)10=(7e)16(126)10mod(7+e)=0。小蓝认为,如果一个整数在二进制、八进制、十进制、十六进制下均为 哈沙德数,那么这个数字就是幸运数字,第 1 至第 10 个幸运数字的十进制表示 为: 1 , 2 , 4 , 6 , 8 , 40 , 48 , 72 , 120 , 126... 1 , 2 , 4 , 6 , 8 , 40 , 48 , 72 , 120 , 126 . . . 1,2,4,6,8,40,48,72,120,126... 。现在他想知道第 2023 个幸运数 字是多少?你只需要告诉小蓝这个整数的十进制表示即可。

【答案提交】

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


215040


模拟。遍历判断即可

	static boolean check(int i) {int x = i;int mod = 0;while(x>0) {mod+= x%2;x>>=1;}if(i%mod !=0) return false;x=i;mod=0;while(x>0) {mod += x%8;x/=8;}if(i%mod !=0) return false;x=i;mod=0;while(x>0) {mod += x%10;x/=10;}if(i%mod !=0) return false;x=i;mod=0;while(x>0) {mod += x%16;x/=16;}if(i%mod !=0) return false;return true;}static void solve() throws IOException{for(int i=1,cnt=0;;i++) {if(check(i)) cnt++;if(cnt==2023) {System.out.println(i);break;}}}

C: 数组分割

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


【问题描述】

小蓝有一个长度为 N N N 的数组 A = [ A 0 , A 1 , . . . , A N − 1 ] A = [A_0, A_1,..., A_{N−1}] A=[A0,A1,...,AN1]。现在小蓝想要从 A A A 对应的数组下标所构成的集合 I = { 0 , 1 , 2 , . . . , N − 1 } I = \{0, 1, 2, . . . , N − 1\} I={0,1,2,...,N1} 中找出一个子集 R 1 R_1 R1,那么 R 1 R_1 R1 I I I 中的补集为 R 2 R_2 R2。记 S 1 = ∑ r ∈ R 1 A r , S 2 = ∑ r ∈ R 2 A r S_1=∑_{r∈R_1}A_r,S_2 =∑_{r∈R2}A_r S1=rR1ArS2=rR2Ar,我们要求 S 1 S_1 S1 S 2 S_2 S2 均为偶数,请问在这种情况下共有多少种不同的 R 1 R_1 R1。当 R 1 R_1 R1 R 2 R_2 R2 为空集时我们将 S 1 S_1 S1 S 2 S_2 S2 视为 0。

【输入格式】

第一行一个整数 T T T,表示有 T T T 组数据。
接下来输入 T T T 组数据,每组数据包含两行:第一行一个整数 N N N,表示数组 A A A 的长度;第二行输入 N N N 个整数从左至右依次为 A 0 , A 1 , . . . , A N − 1 A_0, A_1, . . . , A_{N−1} A0,A1,...,AN1,相邻元素之间用空格分隔。

【输出格式】

对于每组数据,输出一行,包含一个整数表示答案,答案可能会很大,你需要将答案对 1000000007 1000000007 1000000007 进行取模后输出。

【样例输入】

2
2
6 6
2
1 6

【样例输出】

4
0

【提示】

对于第一组数据,答案为 4 4 4。(注意:大括号内的数字表示元素在数组中的下标。)
R 1 = { 0 } , R 2 = { 1 } R_1 = \{0\}, R_2 = \{1\} R1={0},R2={1};此时 S 1 = A 0 = 6 S_1 = A_0 = 6 S1=A0=6 为偶数, S 2 = A 1 = 6 S_2 = A_1 = 6 S2=A1=6 为偶数。
R 1 = { 1 } , R 2 = { 0 } R_1 = \{1\}, R_2 = \{0\} R1={1},R2={0};此时 S 1 = A 1 = 6 S_1 = A_1 = 6 S1=A1=6 为偶数, S 2 = A 0 = 6 S_2 = A_0 = 6 S2=A0=6 为偶数。
R 1 = { 0 , 1 } , R 2 = { } R_1 = \{0, 1\}, R_2 = \{\} R1={0,1},R2={};此时 S 1 = A 0 + A 1 = 12 S_1 = A_0 + A_1 = 12 S1=A0+A1=12 为偶数, S 2 = 0 S_2 = 0 S2=0 为偶数。
R 1 = { } , R 2 = { 0 , 1 } R_1 = \{\}, R_2 = \{0, 1\} R1={},R2={0,1};此时 S 1 = 0 S_1 = 0 S1=0 为偶数, S 2 = A 0 + A 1 = 12 S_2 = A_0 + A_1 = 12 S2=A0+A1=12 为偶数。

对于第二组数据,无论怎么选择,都不满足条件,所以答案为 0。

对于 20% 的评测用例, 1 ≤ N ≤ 10 1 ≤ N ≤ 10 1N10
对于 40% 的评测用例, 1 ≤ N ≤ 1 0 2 1 ≤ N ≤ 10^2 1N102
对于 100% 的评测用例, 1 ≤ T ≤ 10 , 1 ≤ N ≤ 1 0 3 , 0 ≤ A i ≤ 1 0 9 1 ≤ T ≤ 10, 1 ≤ N ≤ 10^3 , 0 ≤ A_i ≤ 10^9 1T10,1N103,0Ai109


逆元 + 组合数

显然总和为奇的答案为0.
总和为偶数的,统计奇数、偶数个数为ji、ou,预处理组合数按式子计算即可.
在这里插入图片描述

化简也是可以的。

    public class Main {static int n,m,mod=(int)1e9+7,maxn=200010;static long ans=0,INF=(long)1e18;static Scanner sc = new Scanner (System.in);public static void main(String[]args) throws IOException{int T = 1;T = sc.nextInt();pre();while(T-->0) solve();}static long fac[] = new long[1002];static long inv[] = new long[1002];static long qpow(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 pre() {fac[0] = inv[0] =1;for(int i=1;i<=1000;i++) {fac[i] = fac[i-1]*i%mod;inv[i] = qpow(fac[i],mod-2);}}static void solve() throws IOException{n = sc.nextInt();int a[] = new int [n+1];int ji=0,ou=0, sum=0;for(int i=1;i<=n;i++) {a[i] = sc.nextInt()%2;if(a[i]%2==0) ou++;else ji++;sum+=a[i];}if(sum%2==1) {System.out.println(0);return;}ans = 0;for(int i=0;i<= ji ; i+=2)ans = (ans + fac[ji]*inv[i]%mod *inv[ji-i]%mod)%mod;long res = 0;for(int i=0;i<= ou ; i++) res = (res + fac[ou]*inv[i]%mod *inv[ou-i]%mod)%mod;System.out.println(ans*res%mod);}}

可能写复杂了。。


D: 矩形总面积

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


【问题描述】

平面上有个两个矩形 R 1 R_1 R1 R 2 R_2 R2,它们各边都与坐标轴平行。设 ( x 1 , y 1 ) (x_1, y_1) (x1,y1) ( x 2 , y 2 ) (x_2, y_2) (x2,y2) 依次是 R 1 R_1 R1 的左下角和右上角坐标, ( x 3 , y 3 ) (x_3, y_3) (x3,y3) ( x 4 , y 4 ) (x_4, y_4) (x4,y4) 依次是 R 2 R_2 R2 的左下角和右上角坐标,请你计算 R 1 R_1 R1 R 2 R_2 R2 的总面积是多少?
注意:如果 R 1 R_1 R1 R 2 R_2 R2 有重叠区域,重叠区域的面积只计算一次。

【输入格式】

输入只有一行,包含 8 个整数,依次是: x 1 , y 1 , x 2 , y 2 , x 3 , y 3 , x 4 x_1,y_1,x_2,y_2,x_3,y_3,x_4 x1,y1,x2,y2,x3,y3,x4 y 4 . y_4. y4.

【输出格式】

一个整数,代表答案。

【样例输入】

2 1 7 4 5 3 8 6

【样例输出】

22

【提示】

对于 20% 的数据, R 1 R_1 R1 R 2 R_2 R2 没有重叠区域。
对于 20% 的数据,其中一个矩形完全在另一个矩形内部。
对于 50% 的数据,所有坐标的取值范围是 [ 0 , 1 0 3 ] [0, 10^3 ] [0,103]
对于 100% 的数据,所有坐标的取值范围是 [ 0 , 1 0 5 ] [0, 10^5 ] [0,105]


分类讨论 or 推结论

两种重合讨论,一种是矩形A至少一个角在矩形B内部;另一种是角都不在互相内部,但是中间部分重合了。注意判断完一次后再交换判断一次。
力扣好像有原题,正解是推结论,c++9行好像就写完了(悲

public class Main{static int maxn = 200005,n,m;static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;static Scanner sc = new Scanner (System.in);public static void main(String[]args) throws IOException{int T = 1;while(T-->0) solve();pw.flush();}static long x1,x2,x3,x4,y1,y2,y3,y4;static boolean check1() { // 四角if(x3 <= x2 && x3 >= x1 && y3 <=y2 && y3 >= y1) {ans -= (Math.min(x2, x4)-x3) *(Math.min(y4, y2)-y3);return true;}if(x4 >= x1 && x4 <= x2 && y3 >=y1 && y3 <= y2) {ans -= (x4 - Math.max(x1, x3)) *(Math.min(y4, y2)-y3);return true;}if(x4 >= x1 && x4 <= x2 && y4 >=y1 && y4 <= y2) {ans -= (x4 - Math.max(x1, x3)) *(y4 - Math.max(y1, y3));return true;}if(x3 >= x1 && x3 <= x2 && y4 >=y1 && y4 <= y2) {ans -= (Math.min(x2, x4)-x3) *(y4 - Math.max(y1, y3));return true;}return false;}static void check2() { //四角都不重合在矩形内部if(x1<x3 && x3 <x2 && x4>x1 && x4 < x2) ans -= (x4-x3) *(y2-y1);if(x1>x3 && x1 <x4 && x2 > x3 && x2 < x4)ans -= (x2-x1)*(y4-y3);}static void solve() throws IOException{x1=sc.nextInt();y1=sc.nextInt();x2=sc.nextInt();y2=sc.nextInt();x3=sc.nextInt();y3=sc.nextInt();x4=sc.nextInt();y4=sc.nextInt();ans = (x2-x1)*(y2-y1) + (x4-x3) *(y4-y3);if(check1()) pw.println(ans);else {long t;t=x1;x1=x3;x3=t;t=x2;x2=x4;x4=t;t=y1;y1=y3;y3=t;t=y2;y2=y4;y4=t;if(check1()) pw.println(ans);else {check2();pw.println(ans);}}}
}

E: 蜗牛

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


【问题描述】

这天,一只蜗牛来到了二维坐标系的原点。
x x x 轴上长有 n n n 根竹竿。它们平行于 y y y 轴,底部纵坐标为 0 0 0,横坐标分别为 x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn。竹竿的高度均为无限高,宽度可忽略。蜗牛想要从原点走到第 n n n 个竹竿的底部也就是坐标 ( x n , 0 ) (x_n, 0) (xn,0)。它只能在 x x x 轴上或者竹竿上爬行,在 x x x 轴上爬行速度为 1 1 1 单位每秒;由于受到引力影响,蜗牛在竹竿上向上和向下爬行的速度分别为 0.7 0.7 0.7 单位每秒和 1.3 1.3 1.3 单位每秒。
为了快速到达目的地,它施展了魔法,在第 i i i i + 1 i + 1 i+1 根竹竿之间建立了传送门 ( 0 < i < n ) (0 < i < n) (0<i<n),如果蜗牛位于第 i i i 根竹竿的高度为 a i a_i ai 的位置 ( x i , a i ) (x_i , a_i) (xi,ai),就可以瞬间到达第 i + 1 i + 1 i+1 根竹竿的高度为 b i + 1 b_{i+1} bi+1 的位置 ( x i + 1 , b i + 1 ) (x_{i+1}, b_{i+1}) (xi+1,bi+1),请计算蜗牛最少需要多少秒才能到达目的地。

【输入格式】

输入共 1 + n 1 + n 1+n 行,第一行为一个正整数 n n n
第二行为 n n n 个正整数 x 1 , x 2 , . . . , x n x_1, x_2, . . . , x_n x1,x2,...,xn
后面 n − 1 n − 1 n1 行,每行两个正整数 a i , b i + 1 a_i , b_{i+1} ai,bi+1

【输出格式】

输出共一行,一个浮点数表示答案(四舍五入保留两位小数)。

【样例输入】

3
1 10 11
1 1
2 1

【样例输出】

4.20

【提示】

蜗牛路线: ( 0 , 0 ) → ( 1 , 0 ) → ( 1 , 1 ) → ( 10 , 1 ) → ( 10 , 0 ) → ( 11 , 0 ) (0, 0) → (1, 0) → (1, 1) → (10, 1) → (10, 0) → (11, 0) (0,0)(1,0)(1,1)(10,1)(10,0)(11,0)
花费时间为 1 + 1 / 0.7 + 0 + 1 / 1.3 + 1 ≈ 4.20 1+1/0.7+0+1/1.3+1 ≈ 4.20 1+1/0.7+0+1/1.3+14.20

对于 20% 的数据,保证 n ≤ 15 n ≤ 15 n15
对于 100% 的数据,保证 n ≤ 1 0 5 , a i , b i ≤ 1 0 4 , x i ≤ 1 0 9 n ≤ 10^5,a_i , b_i ≤ 10^4,x_i ≤ 10^9 n105ai,bi104xi109


线性dp

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示蜗牛走到第 i i i 根杆子的最短用时, j j j 表示状态。
j = 0 j = 0 j=0 : 走到杆子底部
j = 1 j = 1 j=1 :走到杆子的传送门处
P . S . P.S. P.S. 由于只与前一个杆子状态有关,其实用两个变量就行,用二维数组便于理解
时间复杂度: O ( n ) O(n) O(n)


    public class Main{static int maxn = 200005,n,m;static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;static Scanner sc = new Scanner (System.in);static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[]args) throws IOException{int T = 1;//T = Integer.parseInt(S());while(T-->0) solve();pw.flush();}static final int I() throws IOException {st.nextToken();return (int)st.nval;}static void solve() throws IOException{n = sc.nextInt();long x[] = new long [n+1];for(int i=1;i<=n;i++) x[i] = sc.nextInt();int []a = new int [n+1];int []b = new int [n+1];for(int i=1;i<n;i++) {a[i] = sc.nextInt();;b[i] = sc.nextInt();}double dp[][] = new double[n+1][2];dp[1][0] = x[1]; //底端最小用时dp[1][1] = x[1] + a[1] / 0.7;  //传送门用时for(int i=2; i<=n ; i++) {dp[i][0] = Math.min(dp[i-1][0]+x[i]-x[i-1], dp[i-1][1] + b[i-1]/1.3);dp[i][1] = Math.min(dp[i][0] + a[i] / 0.7, dp[i-1][1] + ((b[i-1]>a[i])?(b[i-1]-a[i])/1.3: (a[i]-b[i-1])/0.7));}pw.printf("%.2f",dp[n][0]);}}

F: 合并区域

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


【问题描述】

小蓝在玩一款种地游戏。现在他被分配给了两块大小均为 N × N N × N N×N 的正方形区域。这两块区域都按照 N × N N × N N×N 的规格进行了均等划分,划分成了若干块面积相同的小区域,其中每块小区域要么是岩石,要么就是土壤,在垂直或者水平方向上相邻的土壤可以组成一块土地。现在小蓝想要对这两块区域沿着边缘进行合并,他想知道合并以后可以得到的最大的一块土地的面积是多少(土地的面积就是土地中土壤小区域的块数)?
在进行合并时,小区域之间必须对齐。可以在两块方形区域的任何一条边上进行合并,可以对两块方形区域进行 90 90 90 度、 180 180 180 度、 270 270 270 度、 360 360 360 度的旋转,但不可以进行上下或左右翻转,并且两块方形区域不可以发生重叠。

【输入格式】

第一行一个整数 N N N 表示区域大小。
接下来 N N N 行表示第一块区域,每行 N N N 个值为 0 0 0 1 1 1 的整数,相邻的整数之间用空格进行分隔。值为 0 0 0 表示这块小区域是岩石,值为 1 1 1 表示这块小区域是土壤。
再接下来 N N N 行表示第二块区域,每行 N N N 个值为 0 0 0 1 1 1 的整数,相邻的整数之间用空格进行分隔。值为 0 0 0 表示这块小区域是岩石,值为 1 1 1 表示这块小区域是土壤。

【输出格式】

一个整数表示将两块区域合并之后可以产生的最大的土地面积。

【样例输入】

4
0 1 1 0
1 0 1 1
1 0 1 0
1 1 1 0
0 0 1 0
0 1 1 0
1 0 0 0
1 1 1 1

【样例输出】

15

【提示】

在这里插入图片描述 第一张图展示了样例中的两块区域的布局。第二张图展示了其中一种最佳的合并方式,此时最大的土地面积为 15 15 15

对于 30% 的数据, 1 ≤ N ≤ 5 1 ≤ N ≤ 5 1N5
对于 60% 的数据, 1 ≤ N ≤ 15 1 ≤ N ≤ 15 1N15
对于 100% 的数据, 1 ≤ N ≤ 50 1 ≤ N ≤ 50 1N50


搜索

dotcpp上已更新std。
原先错误std以为只能合并两块,殊不知可以有不止两块合并。

考虑暴力bfs。围绕一块地建图,另一块地在其周围旋转并移动,遍历bfs。遍历至多 4 ∗ 4 ∗ 100 = 1600 4*4*100=1600 44100=1600次,每次bfs复杂度 O ( 100 ∗ 100 ) O(100*100) O(100100),总复杂度 O ( 1600 ∗ 10000 ) = O ( 16 e 6 ) O(1600*10000)=O(16e6) O(160010000)=O(16e6).

2 s 2s 2s内足够了。

import java.io.*;
import java.util.*;public class Main {static int maxn = 200005,n,m;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 int [][]g = new int [500][500];static int w[][] = new int [55][55];static boolean f[][] = new boolean [500][500];static int x1,x2,y1,y2;static void clear(int a,int b) {for(int i=a;i<a+n ; i++)for(int j=b;j<b+n;j++) g[i][j]=0;}static void add(int a,int b,int op) {if(op == 0) {for(int i=a;i<a+n ; i++)for(int j=b;j<b+n;j++) g[i][j]=w[i-a][j-b];}else if(op == 1) { //逆时针1次for(int j = b,u = 0 ; j <b+n ; j++,u++)for(int i = a+n-1,v=0 ; i>=a ; i--,v++) g[i][j] = w[u][v];}else if(op == 2) { //顺时针1次for(int j = b+n-1,u = 0 ; j>=b ; j--,u++)for(int i = a,v=0 ; i<a+n ; i++,v++) g[i][j] = w[u][v];}else { //倒置for(int i = a+n-1,u = 0 ; i >=a ; i--,u++)for(int j = b+n-1,v=0 ; j>=b ; j--,v++) g[i][j] = w[u][v];}}static void ppp() {System.out.println("graph:");for(int i=x1;i<=x2 ; i++) {for(int j=y1;j<=y2 ; j++) {System.out.print(g[i][j]+" ");}System.out.println();}}static int x[] = {1,-1,0,0};static int y[] = {0,0,1,-1};static int bfs(int aa,int bb) {Queue<Integer> q = new LinkedList<>();q.add(aa*1000+bb);int res=0;while(!q.isEmpty()) {int k = q.poll();int a = k/1000,b=k%1000;if(f[a][b]) continue;res++;f[a][b]=true;for(int i=0;i<4;i++) {int xx = a+x[i],yy = y[i]+b;if(xx>=x1 && xx<=x2 && yy>=y1 && yy <=y2 && !f[xx][yy] && g[xx][yy] == 1)q.add(xx*1000+yy);}}return res;}static void work() {int res = 0;for(int u = x1 ; u <= x2 ; u++)for(int v=y1;v<=y2 ; v++) f[u][v]=false;for(int u = x1 ; u <= x2 ; u++)for(int v=y1;v<=y2 ; v++)if(g[u][v] == 1 && !f[u][v]) {res = Math.max(res, bfs(u,v));}m=res;ans = Math.max(ans, res);}static void solve() throws IOException{n = I();for(int i = 60 ; i<60+n ; i++) //第一块区域固定,左上角为 (60,60)for(int j = 60 ; j<60+n ; j++)g[i][j] = I();for(int i = 0;i<n ; i++)for(int j = 0 ; j <n ; j++)w[i][j] = I();for(int i = 60-n+1 ; i <= 60+n-1 ; i++) { //上for(int j=0;j<4;j++) {add(60-n,i,j);x1 =60-n;y1 = Math.min(60, i); x2 = 60+n-1; y2 = Math.max(60+n-1, i+n-1);//ppp();work();//System.out.println(m);clear(60-n,i);}}for(int i = 60-n+1 ; i <= 60+n-1 ; i++) { //下for(int j=0;j<4;j++) {add(60+n,i,j);x1 =60;y1 = Math.min(60, i); x2 = 60+2*n-1; y2 = Math.max(60+n-1, i+n-1);//ppp();work();//System.out.println(m);clear(60+n,i);}}for(int i = 60-n+1 ; i <= 60+n-1 ; i++) { //左for(int j=0;j<4;j++) {add(i,60-n,j);x1 =Math.min(i, 60);y1 = 60-n; x2 = Math.max(i+n-1, 60+n-1); y2 = 60+n-1;//ppp();work();//System.out.println(m);clear(i,60-n);}}for(int i = 60-n+1 ; i <= 60+n-1 ; i++) { //右for(int j=0;j<4;j++) {add(i,60+n,j);x1 =Math.min(i, 60);y1 = 60; x2 = Math.max(i+n-1, 60+n-1); y2 = 60+2*n-1;//ppp();work();//System.out.println(m);clear(i,60+n);}}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 件商品,其中第 i i i 件的价格是 A i A_i Ai。现在该商场正在进行 “买二赠一” 的优惠活动,具体规则是:
每购买 2 2 2 件商品,假设其中较便宜的价格是 P P P(如果两件商品价格一样,则 P P P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P / 2 P/2 P/2 的商品,免费获得这一件商品。可以通过反复购买 2 2 2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。

小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?

【输入格式】

第一行包含一个整数 N N N
第二行包含 N N N 个整数,代表 A 1 , A 2 , A 3 , . . . , A N A_1, A_2, A_3, . . . ,A_N A1,A2,A3,...,AN

【输出格式】

输出一个整数,代表答案。

【样例输入】

7
1 4 2 8 5 7 1

【样例输出】

25

【提示】

小明可以先购买价格 4 4 4 8 8 8 的商品,免费获得一件价格为 1 1 1 的商品;再后买价格为 5 5 5 7 7 7 的商品,免费获得价格为 2 2 2 的商品;最后单独购买剩下的一件价格为 1 1 1 的商品。总计花费 4 + 8 + 5 + 7 + 1 = 25 4 + 8 + 5 + 7 + 1 = 25 4+8+5+7+1=25。不存在花费更低的方案。
对于 30% 的数据, 1 ≤ N ≤ 20 1 ≤ N ≤ 20 1N20
对于 100% 的数据, 1 ≤ N ≤ 5 × 1 0 5 , 1 ≤ A i ≤ 1 0 9 1 ≤ N ≤ 5 × 10^5,1 ≤ Ai ≤ 10^9 1N5×1051Ai109


贪心+二分

先排序,每次贪心地选最大的没买/赠的物品 a , b a,b a,b,然后选剩下的的最大不超过 m i n ( a / 2 , b / 2 ) min(a/2,b/2) min(a/2,b/2)的物品,赠送的物品的价值显然不会增大,故可以二分。

    import java.util.*;import java.io.*;public class Main {static int n,m,mod=(int)1e9+7,maxn=500010;static long ans=0,INF=(long)1e18;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(System.out);public static void main(String[]args) throws IOException{int T = 1;//T = I();while(T-->0) solve();pw.flush();}static int I() throws IOException{st.nextToken();return (int)st.nval;}static int a[] = new int [maxn];static boolean f[] = new boolean [maxn];static int find(int x) {int l=1,r=n;int res =0;while(l<=r) {int mid = (l+r)/2;if(f[mid]) { //先前赠送过,跳到左边r=mid-1;continue;}if(a[mid] <= x) {res = Math.max(res, mid);l = mid+1;}else r = mid-1; }return res;}static void solve() throws IOException{n = I();for(int i=1 ;i<=n;i++) a[i]  =I();Arrays.sort(a,1,n+1);int t = 0;for(int i=n;i>=1;i--) {if(f[i]) continue;//赠送过,跳过ans += a[i];t++;if(t == 2) {t=0;int id = find(a[i]/2);if(id>0) f[id]=true;}}pw.println(ans);}}

H: 合并石子

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


【问题描述】

在桌面从左至右横向摆放着 N N N 堆石子。每一堆石子都有着相同的颜色,颜色可能是颜色 0 0 0,颜色 1 1 1 或者颜色 2 2 2 中的其中一种。
现在要对石子进行合并,规定每次只能选择位置相邻并且颜色相同的两堆石子进行合并。合并后新堆的相对位置保持不变,新堆的石子数目为所选择的两堆石子数目之和,并且新堆石子的颜色也会发生循环式的变化。具体来说:两堆颜色 0 0 0 的石子合并后的石子堆为颜色 1 1 1,两堆颜色 1 1 1 的石子合并后的石子堆为颜色 2 2 2,两堆颜色 2 2 2 的石子合并后的石子堆为颜色 0 0 0。本次合并的花费为所选择的两堆石子的数目之和。
给出 N N N 堆石子以及他们的初始颜色,请问最少可以将它们合并为多少堆石子?如果有多种答案,选择其中合并总花费最小的一种,合并总花费指的是在所有的合并操作中产生的合并花费的总和。

【输入格式】

第一行一个正整数 N N N 表示石子堆数。
第二行包含 N N N 个用空格分隔的正整数,表示从左至右每一堆石子的数目。
第三行包含 N N N 个值为 0 0 0 1 1 1 2 2 2 的整数表示每堆石头的颜色。

【输出格式】

一行包含两个整数,用空格分隔。其中第一个整数表示合并后数目最少的石头堆数,第二个整数表示对应的最小花费。

【样例输入】

5
5 10 1 8 6
1 1 0 2 2

【样例输出】

2 44

【提示】
在这里插入图片描述 上图显示了两种不同的合并方式。其中节点中标明了每一堆的石子数目,在方括号中标注了当前堆石子的颜色属性。左图的这种合并方式最终剩下了两堆石子,所产生的合并总花费为 15 + 14 + 15 = 44 15 + 14 + 15 = 44 15+14+15=44;右图的这种合并方式最终也剩下了两堆石子,但产生的合并总花费为 14 + 15 + 25 = 54 14 + 15 + 25 = 54 14+15+25=54。综上所述,我们选择合并花费为 44 44 44 的这种方式作为答案。
对于 30% 的评测用例, 1 ≤ N ≤ 10 1 ≤ N ≤ 10 1N10
对于 50% 的评测用例, 1 ≤ N ≤ 50 1 ≤ N ≤ 50 1N50
对于 100% 的评测用例, 1 ≤ N ≤ 300 , 1 ≤ 1 ≤ N ≤ 300, 1 ≤ 1N300,1 每堆石子的数目 ≤ 1000 ≤ 1000 1000


区间dp

石子合并裸题。

d p [ i ] [ j ] [ c o l ] dp[i][j][col] dp[i][j][col] 为 合并区间 [ i , j ] [i,j] [i,j] 为一堆,且颜色为 c o l col col 的最小花费,有转移式:
d p [ i ] [ j ] [ ( c o l + 1 ) % 3 ] = m i n ( d p [ i ] [ j ] [ ( c o l + 1 ) % 3 ] , d p [ i ] [ k ] [ c o l ] + d p [ k + 1 ] [ j ] [ c o l ] + s u m [ i ] [ j ] ) dp[i][j][(col+1)\%3] = min(dp[i][j][(col+1)\%3],dp[i][k][col]+dp[k+1][j][col]+sum[i][j]) dp[i][j][(col+1)%3]=min(dp[i][j][(col+1)%3],dp[i][k][col]+dp[k+1][j][col]+sum[i][j]) 其中 s u m [ i ] [ j ] sum[i][j] sum[i][j] 为区间 [ i , j ] [i,j] [i,j] 内石子总数。

为统计最小堆数,设 n u m [ i ] [ j ] num[i][j] num[i][j]为操作合并区间 [ i , j ] [i,j] [i,j]后的最小堆数,初始化为区间长度;更新 d p [ i ] [ j ] dp[i][j] dp[i][j]的同时,更新 n u m [ i ] [ j ] = 1 num[i][j]=1 num[i][j]=1,即合并为1堆。

为统计总共最小花费,设为 c o s t [ i ] [ j ] cost[i][j] cost[i][j],初始化 [ i , j ] [i,j] [i,j]区间能合并为一堆的花费为 m i n ( d p [ i ] [ j ] [ c o l ] ) min(dp[i][j][col]) min(dp[i][j][col]),其他不能合并为1堆的花费初始化为0(因为没有合并,就不用花费),然后用类似 f l o y d floyd floyd的算法转移即可。
复杂度: O ( 3 ∗ n 3 ) O(3*n^3) O(3n3)

import java.io.*;
import java.util.*;
public class Main{static int maxn = 200005,n,m,inf=(int)1e9;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 int dp[][][] = new int [303][303][3];static int num[][] = new int [303][303];static int a[] = new int [301];static int sum[] = new int [301]; //前缀和static int c[] = new int [301];static int cost[][] = new int [303][303];static void solve() throws IOException{n= I();for(int i=1;i<=n;i++)for(int j=i;j<=n;j++) {num[i][j]=j-i+1;for(int k=0;k<3;k++) dp[i][j][k]=inf;}for(int i=1;i<=n;i++) {a[i] = I();sum[i]=a[i]+sum[i-1]; //前缀和,方便统计区间}for(int i=1;i<=n;i++) {c[i] = I();//颜色dp[i][i][c[i]] = 0; //初始石子堆花费显然为0}for(int len=1;len<=n;len++)for(int i=1;i+len-1<=n;i++) {int j=i+len-1;for(int col=0;col<3;col++) {int min = inf;for(int k=i;k<j;k++) {if(dp[i][k][col]!=inf && dp[k+1][j][col]!=inf) {min = Math.min(min, dp[i][k][col] + dp[k+1][j][col]);}}if(min==inf) continue;num[i][j]=1;dp[i][j][(col+1)%3] = Math.min(dp[i][j][(col+1)%3], min+sum[j]-sum[i-1]);cost[i][j] = Math.min(dp[i][j][0], Math.min(dp[i][j][1], dp[i][j][2]));}}for(int k=1;k<=n;k++) for(int i=1;i<=k;i++)for(int j=k+1;j<=n;j++) {if(num[i][j] > num[i][k] + num[k+1][j]) {num[i][j] = num[i][k] + num[k+1][j];cost[i][j] = cost[i][k]+cost[k+1][j];}else if(num[i][j] == num[i][k] + num[k+1][j]) {cost[i][j] = Math.min(cost[i][j], cost[i][k]+cost[k+1][j]);}}pw.println(num[1][n]+" "+cost[1][n]);}
}

I: 最大开支

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


【问题描述】

小蓝所在学校周边新开业了一家游乐园,小蓝作为班长,打算组织大家去游乐园玩。已知一共有 N N N 个人参加这次活动,游乐园有 M M M 个娱乐项目,每个项目都需要买门票后才可进去游玩。门票的价格并不是固定的,团购的人越多单价越便宜,当团购的人数大于某个阈值时,这些团购的人便可以免费进入项目进行游玩。这 M M M 个娱乐项目是独立的,所以只有选择了同一个项目的人才可
以参与这个项目的团购。第 i 个项目的门票价格 H i H_i Hi 与团购的人数 X X X 的关系可以看作是一个函数: H i ( X ) = m a x ( K i × X + B i , 0 ) H_i(X) = max (K_i × X + B_i , 0) Hi(X)=max(Ki×X+Bi,0)
m a x max max 表示取二者之中的最大值。当 H i = 0 H_i = 0 Hi=0 时说明团购人数达到了此项目的免单阈值。
N N N 个人可以根据自己的喜好选择 M M M 个娱乐项目中的一种,或者有些人对这些娱乐项目都没有兴趣,也可以选择不去任何一个项目。每个人最多只会选择一个娱乐项目,如果多个人选择了同一个娱乐项目,那么他们都将享受对应的团购价格。小蓝想知道他至少需要准备多少钱,使得无论大家如何选择,他都有能力支付得起所有 N N N 个人购买娱乐项目的门票钱。

【输入格式】

第一行两个整数 N N N M M M,分别表示参加活动的人数和娱乐项目的个数。
接下来 M M M 行,每行两个整数,其中第 i i i 行为 K i 、 B i K_i、B_i KiBi,表示第 i 个游乐地点的门票函数中的参数。

【输出格式】

一个整数,表示小蓝至少需要准备多少钱,使得大家无论如何选择项目,自己都支付得起。

【样例输入】

4 2
-4 10
-2 7

【样例输出】

12

【提示】

样例中有 4 4 4 个人, 2 2 2 个娱乐项目,我们用一个二元组 ( a , b ) (a, b) (a,b) 表示 a a a 个人选择了第一个娱乐项目, b b b 个人选择了第二个娱乐项目,那么就有 4 − a − b 4 − a − b 4ab 个人没有选择任何项目,方案 ( a , b ) (a, b) (a,b) 对应的门票花费为 m a x ( − 4 × a + 10 , 0 ) × a + m a x ( − 2 × b + 7 , 0 ) × b max(−4 × a + 10, 0) × a +max(−2 × b + 7, 0) × b max(4×a+10,0)×a+max(2×b+7,0)×b,所有的可能如下所示:

ab花费
000
015
026
033
040
106
1111
1212
139
204
219
2210
300
315
400

其中当 a = 1 a = 1 a=1, b = 2 b = 2 b=2 时花费最大,为 12 12 12。此时 1 1 1 个人去第一个项目,所以第一个项目的单价为 10 − 4 = 6 10 − 4 = 6 104=6,在这个项目上的花费为 6 × 1 = 6 6 × 1 = 6 6×1=6 2 2 2 个人去第二个项目,所以第二个项目得单价为 7 − 2 × 2 = 3 7 − 2 × 2 = 3 72×2=3,在这个项目上的花费为 2 × 3 = 6 2 × 3 = 6 2×3=6;还有 1 1 1 个人没去任何项目,不用统计;总花费为 12 12 12,这是花费最大的一种方案,所以答案为 12 12 12
对于 30% 的评测用例, 1 ≤ N , M ≤ 10 1 ≤ N, M ≤ 10 1N,M10
对于 50% 的评测用例, 1 ≤ N , M ≤ 1000 1 ≤ N, M ≤ 1000 1N,M1000
对于 100% 的评测用例, 1 ≤ N , M , B i ≤ 1 0 5 , − 1 0 5 ≤ K i < 0 。 1 ≤ N, M, B_i ≤ 10^5,−10^5 ≤ K_i < 0。 1N,M,Bi105105Ki<0


贪心 + 优先队列

将所有项目扔到堆里,按项目游玩人数+1 的开支变化量降序排序,贪心取变化最大的即可。
变化量小于等于 0 时退出循环。

import java.io.*;
import java.util.*;
public class Main{static int maxn = 200005,n,m;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 node implements Comparable<node>{long k=0,b=0;int num=0;public node(long a,long bb) {k=a;b=bb;}@Overridepublic int compareTo(node o) {// TODO Auto-generated method stublong x = (this.num+1)*Math.max(0, k*(num+1)+b) - num*Math.max(0, k*num+b);long y =  (o.num+1)*Math.max(0, o.k*(o.num+1)+o.b) - o.num*Math.max(0, o.k*o.num+o.b);return x<y?1:-1;}}static void solve() throws IOException{n=I();m=I();PriorityQueue<node> q = new PriorityQueue<>();for(int i=0;i<m;i++) {long k=I(),b=I();q.add(new node(k,b));}while(n-->0) {node o = q.poll();if((o.num+1)*Math.max(0, o.k*(o.num+1)+o.b) - o.num*Math.max(0, o.k*o.num+o.b)<=0) {q.add(o);break;}o.num++;q.add(o);}while(!q.isEmpty()) {node o = q.poll();ans += o.num*Math.max(0, o.k*o.num+o.b);}pw.println(ans);}
}

借用肖哥一句话:为什么就不能把贪心从考纲里划掉呢?(滑稽


J: 魔法阵

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


【问题描述】

魔法师小蓝为了营救自己的朋友小 Q Q Q,来到了敌人布置的魔法阵。魔法阵可以看作是一幅具有 N N N 个结点 M M M 条边的无向图,结点编号为 0 , 1 , 2 , . . . , N − 1 0, 1, 2, . . . , N−1 0,1,2,...,N1,图中没有重边和自环。敌人在每条边上都布置了陷阱,每条边都有一个伤害属性 w w w,每当小蓝经过一条边时就会受到这条边对应的 w w w 的伤害。小蓝从结点 0出发,沿着边行走,想要到达结点 N − 1 N−1 N1 营救小 Q Q Q
小蓝有一种特殊的魔法可以使用,假设一条路径按照顺序依次经过了以下 L L L 条边: e 1 , e 2 , . . . , e L e_1, e_2, . . . , e_L e1,e2,...,eL(可以出现重复的边),那么期间小蓝受到的总伤害就是 P = ∑ i = 1 L w ( e i ) P = ∑_{i=1}^L w(e_i) P=i=1Lw(ei) w ( e i ) w(e_i) w(ei) 表示边 e i e_i ei 的伤害属性。如果 L ≥ K L≥K LK,那么小蓝就可以从这 L L L条边当中选出连续出现的 K K K条边 e c , e c + 1 , . . . , e c + K − 1 e_c , e_{c+1}, . . . , e_{c+K−1} ec,ec+1,...,ec+K1 并免去在这 K K K 条边行走期间所受到的伤害,即使用魔法之后路径总伤害变为 P ′ = P − ∑ i = c c + K − 1 w ( e i ) P^′ = P −∑_{i=c}^{c+K-1}w(e_i) P=Pi=cc+K1w(ei)
注意必须恰好选出连续出现的 K K K 条边,所以当 L < K L < K L<K 时无法使用魔法。
小蓝最多只可以使用一次上述的魔法,请问从结点 0 0 0 出发到结点 N − 1 N − 1 N1 受到的最小伤害是多少?题目保证至少存在一条从结点 0 0 0 N − 1 N − 1 N1 的路径。

【输入格式】

第一行输入三个整数, N N N, K K K, M M M,用空格分隔。
接下来 M M M 行,每行包含三个整数 u , v , w u,v,w u,v,w,表示结点 u u u 与结点 v v v 之间存在一条伤害属性为 w w w 的无向边。

【输出格式】

输出一行,包含一个整数,表示小蓝从结点 0 0 0 到结点 N − 1 N − 1 N1 受到的最小伤害。

【样例输入】

4 2 3
0 1 2
1 2 1
2 3 4

【样例输出】

2

【提示】

样例 1,存在路径: 0 → 1 → 2 → 3 , K = 2 0 → 1 → 2 → 3,K = 2 0123K=2,如果在 0 → 1 → 2 0 → 1 → 2 012 上使用魔法,那么答案就是 0 + 0 + 4 = 4 0 + 0 + 4 = 4 0+0+4=4;如果在 1 → 2 → 3 1 → 2 → 3 123 上使用魔法,那么答案就是 2 + 0 + 0 = 2 2 + 0 + 0 = 2 2+0+0=2。再也找不到比 2 2 2 还小的答案了,所以答案就是 2 2 2

对于 30% 的评测用例, 1 ≤ N ≤ 20 1 ≤ N ≤ 20 1N20
对于 50% 的评测用例, 1 ≤ N ≤ 100 1 ≤ N ≤ 100 1N100
对于 100% 的评测用例, 1 ≤ N ≤ 1000 , 1 ≤ M ≤ N × ( N − 1 ) / 2 , 1 ≤ K ≤ 10 , 0 ≤ u , v ≤ N − 1 , 1 ≤ w ≤ 1000 1 ≤ N ≤ 1000, 1 ≤ M ≤ N×(N−1)/2,1 ≤ K ≤ 10,0 ≤ u, v ≤ N − 1,1 ≤ w ≤ 1000 1N1000,1MN×(N1)/21K100u,vN11w1000


最短路+简单dp

同比C++压轴题,似乎容易了些。(至少比去年好,超级大模拟,哪里来的天才出题人)

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从 0 0 0 跑到 i i i ,且消除 j j j 条连续边伤害的最小伤害。显然 j = 0 j=0 j=0 时,表示不使用魔法。

D i j k s t r a Dijkstra Dijkstra 算法中,每次从未确定最短路的结点中选择距离起点最近的结点 u u u,然后更新与 u u u 相邻的结点的最短路,总复杂度差不多为 O ( n 2 ) O(n^2) O(n2)。对于每个相邻结点 v v v,我们需要考虑三种情况:

(1) 如果不使用魔法,显然是普通最短路算法。若当前路径长度 d p [ u ] [ 0 ] + w ( u , v ) < d p [ v ] [ 0 ] dp[u][0]+w(u,v)<dp[v][0] dp[u][0]+w(u,v)<dp[v][0],那么更新 d p [ v ] [ 0 ] = d p [ u ] [ 0 ] + w ( u , v ) dp[v][0]=dp[u][0]+w(u,v) dp[v][0]=dp[u][0]+w(u,v),表示不使用魔法的最小伤害。
(2) 使用魔法,有转移式: d p [ v ] [ j ] = m i n ( d p [ v ] [ j ] , d p [ u ] [ j − 1 ] ) dp[v][j]=min(dp[v][j],dp[u][j-1]) dp[v][j]=min(dp[v][j],dp[u][j1]);
(3) 已经连续消除 k k k 条边的伤害,正常转移: d p [ v ] [ k ] = m i n ( d p [ v ] [ k ] , d p [ u ] [ k ] + w ( u , v ) ) dp[v][k]=min(dp[v][k],dp[u][k]+w(u,v)) dp[v][k]=min(dp[v][k],dp[u][k]+w(u,v));

小蓝继续努力吧。

import java.io.*;
import java.util.*;
public class Main{static int maxn = 200005,n,m,inf=(int)1e9;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 node{int to;int w;public node(int a,int b) {to=a;w=b;}}static Vector<Vector<node>> g =new Vector<>();static int k=0;static int d[][] = new int [1001][11];static int cnt=0;static void dij() {for(int i=0;i<n;i++)for(int j=0;j<=k;j++) d[i][j] = inf;d[0][0]=0;Queue<Integer> q = new LinkedList<>();q.add(0);while(!q.isEmpty()) {int x = q.poll();for(node o:g.get(x)) {int y = o.to,w = o.w;boolean f = false;if(d[y][0] > d[x][0]+w) {d[y][0] = d[x][0]+w;f=true;}for(int j=1;j<=k;j++) {if(d[y][j] > d[x][j-1]) {d[y][j] = d[x][j-1];f=true;}}if(d[y][k] > d[x][k]+w) {f=true;d[y][k] = d[x][k]+w;}if(f) q.add(y);}}}static void solve() throws IOException{n=I();k=I();m=I();for(int i=0;i<n;i++) g.add(new Vector<>());while(m-->0) {int u=I(),v=I(),w=I();g.get(u).add(new node(v,w));g.get(v).add(new node(u,w));}dij();pw.println(Math.min(d[n-1][0], d[n-1][k]));}
}

制作不易,喜欢的话点个赞吧!谢谢~

这篇关于2023年第十四届蓝桥杯省赛JavaB组个人题解(AK)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/333552

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定