一、暴力枚举 / 模拟
1. 两数之和
① HashMap 相关方法:
hashmap.containsKey():返回 boolean 类型,用于判断是否包含指定键hashmap.get():获取对应键的 value 值
49. 字母异位词分组
① List 与 Set 区别:
- List:允许重复、有序,可通过下标
get(i)获取元素 - Set:不允许重复、无序,不能通过
get(i)获取元素
② 字符串转数组方法:
java
char[] array = str.toCharArray();
③ 对数组排序:
java
Arrays.sort(数组名);
④ List 初始化与使用:
java
List<String> list = map.getOrDefault(key, new ArrayList<>());
// list 使用方法
① add(添加元素)
java
// 运行
list.add("张三");
list.add("李四");
list.add("王五");
// 现在 list:[张三, 李四, 王五]
② get(获取第几个元素,从 0 开始)
java
// 运行
String name = list.get(0); // 获取第 0 个 → "张三"
String name2 = list.get(1); // 获取第 1 个 → "李四"
③ set(修改某个位置的值)
java
// 运行
list.remove(0); // 删除下标 0
// 现在 list:[赵六, 王五]
④ remove(删除)
-
方式 1:按下标删除
java// 运行 list.remove(0); // 删除下标 0 // 现在 list:[赵六, 王五] -
方式 2:按内容删除
java// 运行 list.remove("王五"); // 现在 list:[赵六]
⑤indexOf(找元素的下标)
java
// 运行
int index = list.indexOf("赵六"); // 返回 0
int no = list.indexOf("不存在"); // 找不到返回 -1
⑥ contains(判断是否包含某个元素)
java
// 运行
boolean has = list.contains("赵六"); // true
boolean no = list.contains("张三"); // false
① map.keySet()
- 作用:返回一个包含 Map 中所有键(key)的 Set 集合。
java
// 假设已有一个 Map
Map<String, Integer> map = new HashMap<>();
map.put("张三", 20);
map.put("李四", 25);
// 获取所有键的集合
Set<String> keys = map.keySet();
// 遍历所有键
for (String key : keys) {
System.out.println("键: " + key);
}
// 输出:
// 键: 张三
// 键: 李四
② map.values()
-
作用:返回一个包含 Map 中所有值(value)的 Collection 集合。
java// 假设已有一个 Map Map<String, Integer> map = new HashMap<>(); map.put("张三", 20); map.put("李四", 25); // 获取所有值的集合 Collection<Integer> values = map.values(); // 遍历所有值 for (Integer value : values) { System.out.println("值: " + value); } // 输出: // 值: 20 // 值: 25
二、2025年真题
3313.电池分组
1.题目描述
研究员小蓝受到实验室主任的指示,需要对实验室新研发的 N 个新型能量 电池进行分组实验。这 N 个能量电池的能量值分别用 A1, A2, . . . , AN 表示,每个 能量值都是一个整数。为了保证实验的安全性,小蓝需要将这 N 个能量电池分 成两组,使得这两组能量电池的能量值异或和相等。
能量值的异或和计算方法如下:对于一个集合 S,其异或和等于集合中所 有元素的按位异或结果。例如,集合 {1, 2, 3} 的异或和为 1 ⊕ 2 ⊕ 3 = 0,其中 ⊕ 表示异或运算。
现在,小蓝想知道,这 N 个能量电池能否分成两组,使得这两组能量电池 的能量值异或和相等。注意,每组至少包含一个能量电池。
2.输入格式
输入的第一行包含一个整数 T ,表示测试用例的数量。
每个测试用例占两行:
第一行包含一个整数 N,表示能量电池的数量。
第二行包含 N 个整数 A1, A2, . . . , AN,表示每个能量电池的能量值。
3.重要知识点:异或^
1). 什么是 异或(⊕ / XOR)
就是一种 二进制按位计算,规则只有 4 句:
- 0 ⊕ 0 = 0
- 0 ⊕ 1 = 1
- 1 ⊕ 0 = 1
- 1 ⊕ 1 = 0
口诀:相同为 0,不同为 1
先转二进制:
- 1 → 01
- 2 → 10
- 3 → 11
一步步算:
1 ⊕ 2 = 01 ⊕ 10 = 11(=3)
3 ⊕ 3 = 11 ⊕ 11 = 00(=0)
所以:
1 ⊕ 2 ⊕ 3 = 0
4.代码
java
package text;
import java.util.*;
public class test1 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner scan=new Scanner(System.in);
int T=scan.nextInt();
while(T-->0) {
int N=scan.nextInt();
int sum=0;
for(int i=0;i<N;i++) {
int a=scan.nextInt();
sum^=a;
}
System.out.println(sum==0?"YES":"NO");
}
}
}
3314.魔法科考试
找质数:
java
boolean [] isPrime=new boolean[max + 5];
for(int i=2;i<=max;i++) {
isPrime[i]=true;
}
for(int i=2;i*i<=max;i++) {
if(isPrime[i]) {
for(int j=i*i;j<=max;j+=i) {
isPrime[j]=false;
}
}
}
P1918 保龄球
题目描述
DL 算缘分算得很烦闷,所以常常到体育馆去打保龄球解闷。因为他保龄球已经打了几十年了,所以技术上不成问题,于是他就想玩点新花招。
DL 的视力真的很不错,竟然能够数清楚在他前方十米左右每个位置的瓶子的数量。他突然发现这是一个炫耀自己好视力的借口------他看清远方瓶子的个数后从某个位置发球,这样就能打倒一定数量的瓶子。

如上图,每个 " ◯ \bigcirc ◯" 代表一个瓶子。如果 DL 想要打倒 3 3 3 个瓶子就在 1 1 1 位置发球,想要打倒 4 4 4 个瓶子就在 2 2 2 位置发球。
现在他想要打倒 m m m 个瓶子。他告诉你每个位置的瓶子数,请你给他一个发球位置。
输入格式
第一行包含一个正整数 n n n,表示位置数。
第二行包含 n n n 个正整数 a i a_i ai ,表示第 i i i 个位置的瓶子数,保证各个位置的瓶子数不同。
第三行包含一个正整数 Q Q Q,表示 DL 发球的次数。
第四行至文件末尾,每行包含一个正整数 m m m,表示 DL 需要打倒 m m m 个瓶子。
输出格式
共 Q Q Q 行。每行包含一个整数,第 i i i 行的整数表示 DL 第 i i i 次的发球位置。若无解,则输出 0 0 0。
输入输出样例 #1
输入 #1
5
1 2 4 3 5
2
4
7
输出 #1
3
0
说明/提示
【数据范围】
对于 50 % 50\% 50% 的数据, 1 ≤ n , Q ≤ 1000 , 1 ≤ a i , m ≤ 10 5 1 \leq n, Q \leq 1000, 1 \leq a_i, m \leq 10^5 1≤n,Q≤1000,1≤ai,m≤105。
对于 100 % 100\% 100% 的数据, 1 ≤ n , Q ≤ 100000 , 1 ≤ a i , m ≤ 10 9 1 \leq n,Q \leq 100000, 1 \leq a_i, m \leq 10^9 1≤n,Q≤100000,1≤ai,m≤109。
代码:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
Map <Integer,Integer> map=new HashMap<>();
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
int a;
for(int i=1;i<=n;i++) {
a=Integer.parseInt(stringTokenizer.nextToken());
map.put(a, i);
}
int Q=Integer.parseInt(br.readLine());
int [] arr=new int[Q];
for(int i=0;i<Q;i++) {
arr[i]=Integer.parseInt(br.readLine());
}
StringBuilder sBuilder=new StringBuilder();
for(int b:arr) {
if(map.containsKey(b)) {
sBuilder.append(map.get(b)).append("\n");
}else {
sBuilder.append("0\n");
}
}
System.out.println(sBuilder);
}
}
!NOTE
🔥 终极口诀(背这个)
- 一行只有一个数 → 用 br.readLine()
- 一行有好多个数 → 用 StringTokenizer + nextToken()
!CAUTION
当出现MLE的时候可以采用快读快写的方式,但是要注意的是main方法后面要添加·throws IOException·
P1102 A-B 数对
时间限制: 1.00s 内存限制: 125.00MB
复制 Markdown\](javascript:void 0)
\[ 中文\](javascript:void 0)
\[ 退出 IDE 模式\](javascript:void 0)
### 题目背景
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
### 题目描述
给出一串正整数数列以及一个正整数 *C* ,要求计算出所有满足 *A* −*B* =*C* 的数对的个数(不同位置的数字一样的数对算不同的数对)。
### 输入格式
输入共两行。
第一行,两个正整数 *N* ,*C*。
第二行,*N* 个正整数,作为要求处理的那串数。
### 输出格式
一行,表示该串正整数中包含的满足 *A* −*B* =*C* 的数对的个数。
### 输入输出样例
**输入 #1**复制运行
4 1
1 1 2 3
**输出 #1**复制运行
3
### 说明/提示
对于 75% 的数据,1≤*N*≤2000。
对于 100% 的数据,1≤*N* ≤2×105,0≤*a\*\*i* \<230,1≤*C*\<230。
2017/4/29 新添数据两组
#### 代码
```java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
int N=Integer.parseInt(st.nextToken());
long C=Long.parseLong(st.nextToken());
st=new StringTokenizer(br.readLine());
long []arr=new long[N];
Map
无符号输入:parseUnsignedLong()
无符号输出:Long.toUnsignedString()
P3131 [USACO16JAN] Subsequences Summing to Sevens S
题目描述
Farmer John 的 N N N 头奶牛站成一排,这是它们时不时会做的事情。每头奶牛都有一个独特的整数 ID 编号,以便 Farmer John 能够区分它们。Farmer John 希望为一组连续的奶牛拍照,但由于童年时与数字 1 ... 6 1 \ldots 6 1...6 相关的创伤事件,他只希望拍摄一组奶牛,如果它们的 ID 加起来是 7 7 7 的倍数。
请帮助 Farmer John 确定他可以拍摄的最大奶牛组的大小。
输入格式
输入的第一行包含 N N N( 1 ≤ N ≤ 50 , 000 1 \leq N \leq 50,000 1≤N≤50,000)。接下来的 N N N 行每行包含一头奶牛的整数 ID(所有 ID 都在 0 ... 1 , 000 , 000 0 \ldots 1,000,000 0...1,000,000 范围内)。
输出格式
请输出 ID 之和为 7 7 7 的倍数的最大连续奶牛组中的奶牛数量。如果不存在这样的组,则输出 0 0 0。
输入输出样例 #1
输入 #1
7
3
5
1
6
2
14
10
输出 #1
5
说明/提示
在这个例子中, 5 + 1 + 6 + 2 + 14 = 28 5+1+6+2+14 = 28 5+1+6+2+14=28。
代码
java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
long []pre=new long[n+1];
int y;
for(int i=1;i<=n;i++){
y=Integer.parseInt(br.readLine());
pre[i]=pre[i-1]+y;
}
int []first=new int[7];
for(int i = 0; i < 7; i++){
first[i] = -1;
}
int max=0;
first[0]=0;
for(int i=1;i<=n;i++){
int num=(int)(pre[i]%7);
if(num<0){
num+=7;
}
if(first[num]!=-1){
max=Math.max(max,i-first[num]);
}else{
first[num]=i;
}
}
System.out.print(max);
}
}
P8649 [蓝桥杯 2017 省 B] k 倍区间
题目描述
给定一个长度为 N N N 的数列, A 1 , A 2 , ⋯ A N A_1,A_2, \cdots A_N A1,A2,⋯AN,如果其中一段连续的子序列 A i , A i + 1 , ⋯ A j ( i ≤ j ) A_i,A_{i+1}, \cdots A_j(i \le j) Ai,Ai+1,⋯Aj(i≤j) 之和是 K K K 的倍数,我们就称这个区间 [ i , j ] [i,j] [i,j] 是 K K K 倍区间。
你能求出数列中总共有多少个 K K K 倍区间吗?
输入格式
第一行包含两个整数 N N N 和 K K K ( 1 ≤ N , K ≤ 10 5 ) (1 \le N,K \le 10^5) (1≤N,K≤105)。
以下 N N N 行每行包含一个整数 A i A_i Ai ( 1 ≤ A i ≤ 10 5 ) (1 \le A_i \le 10^5) (1≤Ai≤105)。
输出格式
输出一个整数,代表 K K K 倍区间的数目。
输入输出样例 #1
输入 #1
5 2
1
2
3
4
5
输出 #1
6
说明/提示
时限 2 秒, 256M。蓝桥杯 2017 年第八届
代码
java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
int n=Integer.parseInt(st.nextToken());
int k=Integer.parseInt(st.nextToken());
long [] pre=new long [n+1];
int num=0;
for(int i=1;i<n+1;i++){
num=Integer.parseInt(br.readLine());
pre[i]=pre[i-1]+num;
}
long []first=new long[k];
// for(int i=0;i<k;i++){
// first[i]=-1;
// }
first[0]=1L;
long sum=0;
for(int i=1;i<=n;i++){
int b=(int)(pre[i]%k);
if(b<0){
b+=k;
}
first[b]+=1L;
}
for(int i=0;i<k;i++){
sum+=first[i]*(first[i]-1)/2;
}
System.out.println(sum);
}
}
P1464 [PacNW 1999] Function
题目描述
对于一个递归函数 w ( a , b , c ) w(a,b,c) w(a,b,c)
- 如果 a ≤ 0 a \le 0 a≤0 或 b ≤ 0 b \le 0 b≤0 或 c ≤ 0 c \le 0 c≤0 就返回值 1 1 1。
- 如果 a > 20 a>20 a>20 或 b > 20 b>20 b>20 或 c > 20 c>20 c>20 就返回 w ( 20 , 20 , 20 ) w(20,20,20) w(20,20,20)
- 如果 a < b a<b a<b 并且 b < c b<c b<c 就返回 w ( a , b , c − 1 ) + w ( a , b − 1 , c − 1 ) − w ( a , b − 1 , c ) w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c) w(a,b,c−1)+w(a,b−1,c−1)−w(a,b−1,c)。
- 其它的情况就返回 w ( a − 1 , b , c ) + w ( a − 1 , b − 1 , c ) + w ( a − 1 , b , c − 1 ) − w ( a − 1 , b − 1 , c − 1 ) w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1) w(a−1,b,c)+w(a−1,b−1,c)+w(a−1,b,c−1)−w(a−1,b−1,c−1)
这是个简单的递归函数,但实现起来可能会有些问题。当 a , b , c a,b,c a,b,c 均为 15 15 15 时,调用的次数将非常的多。你要想个办法才行。
注意:例如 w ( 30 , − 1 , 0 ) w(30,-1,0) w(30,−1,0) 又满足条件 1 1 1 又满足条件 2 2 2,请按照最上面的条件来算,答案为 1 1 1。
输入格式
会有若干行。
并以 − 1 , − 1 , − 1 -1,-1,-1 −1,−1,−1 结束。
输出格式
输出若干行,每一行格式:
w(a, b, c) = ans
注意空格。
输入输出样例 #1
输入 #1
1 1 1
2 2 2
-1 -1 -1
输出 #1
w(1, 1, 1) = 2
w(2, 2, 2) = 4
说明/提示
数据规模与约定
保证输入的数在 [ − 9223372036854775808 , 9223372036854775807 ] [-9223372036854775808,9223372036854775807] [−9223372036854775808,9223372036854775807] 之间,并且是整数。
保证不包括 − 1 , − 1 , − 1 -1, -1, -1 −1,−1,−1 的输入行数 T T T 满足 1 ≤ T ≤ 10 5 1 \leq T \leq 10 ^ 5 1≤T≤105。
代码
java
import java.io.*;
import java.util.*;
public class Main {
static long[][][] dp = new long[25][25][25];
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
while(true){
StringTokenizer st=new StringTokenizer(br.readLine());
long a=Long.parseLong(st.nextToken());
long b=Long.parseLong(st.nextToken());
long c=Long.parseLong(st.nextToken());
if(a==-1&&b==-1&&c==-1){
break;
}
long sum=w(a,b,c);
System.out.println("w("+a+", "+b+", "+c+") = "+sum);
}
}
static public long w(long a,long b,long c){
int x=(int)a;
int y=(int)b;
int z=(int)c;
if(a<=0||b<=0||c<=0){
return 1;
}else if(a>20||b>20||c>20){
dp[20][20][20]=w(20, 20, 20);
return dp[20][20][20];
}else {
if(a<b&&b<c) {
if(dp[x][y][z-1]==0) {
dp[x][y][z-1]= w(a, b, c-1);
} if(dp[x][y-1][z-1]==0) {
dp[x][y-1][z-1]= w(a, b-1, c-1);
} if(dp[x][y-1][z]==0) {
dp[x][y-1][z]= w(a, b-1, c);
}
dp[x][y][z]=dp[x][y][z-1]+dp[x][y-1][z-1]-dp[x][y-1][z];
}else {
if(dp[x-1][y][z]==0) {
dp[x-1][y][z]= w(a-1, b, c);
} if(dp[x-1][y-1][z]==0) {
dp[x-1][y-1][z]= w(a-1, b-1, c);
} if(dp[x-1][y][z-1]==0) {
dp[x-1][y][z-1]= w(a-1, b, c-1);
} if(dp[x-1][y-1][z-1]==0) {
dp[x-1][y-1][z-1]= w(a-1, b-1, c-1);
}
dp[x][y][z]=dp[x-1][y][z]+dp[x-1][y-1][z]+dp[x-1][y][z-1]-dp[x-1][y-1][z-1];
}
return dp[x][y][z];
}
}
}
P2036 [COCI 2008/2009 #2] PERKET
题目描述
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 n n n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s s s 和苦度 b b b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物是只以水为配料的。
输入格式
第一行一个整数 n n n,表示可供选用的食材种类数。
接下来 n n n 行,每行 2 2 2 个整数 s i s_i si 和 b i b_i bi,表示第 i i i 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例 #1
输入 #1
1
3 10
输出 #1
7
输入输出样例 #2
输入 #2
2
3 8
5 8
输出 #2
1
输入输出样例 #3
输入 #3
4
1 7
2 6
3 8
4 9
输出 #3
1
说明/提示
对于第三组样例,选择最后三种食材,此时的总酸度为 2 × 3 × 4 = 24 2 \times 3 \times 4 = 24 2×3×4=24,总苦度为 6 + 8 + 9 = 23 6+8+9=23 6+8+9=23,差值为 1 1 1。
数据规模与约定
对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 10 1 \leq n \leq 10 1≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1 × 10 9 1 \times 10^9 1×109。
说明
- 本题满分 70 70 70 分。
- 题目译自 COCI2008-2009 CONTEST #2 PERKET,译者 @mnesia。
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int []suan;
static int []ku;
static int min=Integer.MAX_VALUE;
static int n;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(br.readLine());
suan=new int[n+1];
ku=new int[n+1];
for(int i=1;i<=n;i++) {
StringTokenizer st=new StringTokenizer(br.readLine());
suan[i]=Integer.parseInt(st.nextToken());
ku[i]=Integer.parseInt(st.nextToken());
}
dfs(1, 1, 0);
System.out.println(min);
}
static public void dfs(int i,int a,int b) {
if(i>n) {
if(a==1&&b==0) return;
min=Math.min(min, Math.abs(a-b));
}else {
dfs(i+1, a, b);
dfs(i+1, a*suan[i], b+ku[i]);
}
}
}
P1101 单词方阵
题目描述
给一 n × n n \times n n×n 的字母方阵,内可能蕴含多个 yizhong 单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8 8 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用 * 代替,以突出显示单词。
输入格式
第一行输入一个数 n n n。 ( 7 ≤ n ≤ 100 ) (7 \le n \le 100) (7≤n≤100)。
第二行开始输入 n × n n \times n n×n 的字母矩阵。
输出格式
突出显示单词的 n × n n \times n n×n 矩阵。
输入输出样例 #1
输入 #1
7
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
aaaaaaa
输出 #1
*******
*******
*******
*******
*******
*******
*******
输入输出样例 #2
输入 #2
8
qyizhong
gydthkjy
nwidghji
orbzsfgz
hhgrhwth
zzzzzozo
iwdfrgng
yyyygggg
输出 #2
*yizhong
gy******
n*i*****
o**z****
h***h***
z****o**
i*****n*
y******g
代码
java
import java.util.*;
import java.io.*;
public class Main {
// static int []dx={-1,-1,0,1,1,1,0,-1};
// static int []dy={0,1,1,1,0,-1,-1,-1};
static int[] dx = {-1,-1,-1, 0,0, 1,1,1};
static int[] dy = {-1,0,1, -1,1, -1,0,1};
static String string="yizhong";
static char [][]arr;
static int n;
static boolean [][]flag;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(br.readLine());
flag=new boolean[n+5][n+5];
arr=new char[n+5][n+5];
for(int i=0;i<n;i++) {
arr[i]=br.readLine().toCharArray();
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(arr[i][j]=='y') {
for(int k=0;k<8;k++) {
dfs(i,j,k,0);
}
}
}
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(flag[i][j]) {
System.out.print(arr[i][j]);
}
else {
System.out.print("*");
}
}
System.out.print("\n");
}
}
static public boolean dfs(int i,int j,int k,int idx) {
if(i<0||i>=n||j<0||j>=n) {
return false;
}
if(arr[i][j]!=string.charAt(idx)) return false;
if(idx==6) {
flag[i][j]=true;
return true;
}
int ni=i+dx[k];
int nj=j+dy[k];
if(dfs(ni, nj, k, idx+1)){
if(flag[ni][nj]) {
flag[i][j]=true;
return true;
}
}
return false;
}
}
P1162 填涂颜色
题目描述
由数字 0 0 0 组成的方阵中,有一任意形状的由数字 1 1 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 2 2 2。例如: 6 × 6 6\times 6 6×6 的方阵( n = 6 n=6 n=6),涂色前和涂色后的方阵如下:
如果从某个 0 0 0 出发,只向上下左右 4 4 4 个方向移动且仅经过其他 0 0 0 的情况下,无法到达方阵的边界,就认为这个 0 0 0 在闭合圈内 。闭合圈不一定是环形的,可以是任意形状,但保证闭合圈内 的 0 0 0 是连通的(两两之间可以相互到达)。
plain
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 1 0 1
1 1 1 1 1 1
plain
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 1 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数 n ( 1 ≤ n ≤ 30 ) n(1 \le n \le 30) n(1≤n≤30)。
接下来 n n n 行,由 0 0 0 和 1 1 1 组成的 n × n n \times n n×n 的方阵。
方阵内只有一个闭合圈,圈内至少有一个 0 0 0。
输出格式
已经填好数字 2 2 2 的完整方阵。
输入输出样例 #1
输入 #1
6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
输出 #1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
说明/提示
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 30 1 \le n \le 30 1≤n≤30。
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int [][]arr;
static int n;
static int[]dx= {-1,0,1,0};
static int[]dy= {0,1,0,-1};
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(br.readLine());
arr=new int[n+5][n+5];
for(int i=0;i<n;i++) {
StringTokenizer st=new StringTokenizer(br.readLine());
for(int j=0;j<n;j++) {
arr[i][j]=Integer.parseInt(st.nextToken());
}
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if((i==0||i==n-1||j==0||j==n-1)&&arr[i][j]==0) {
dfs(i,j);
}
}
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(arr[i][j]==3) {
System.out.print(0+" ");
}else if(arr[i][j]==1) {
System.out.print(1+" ");
}else {
System.out.print(2+" ");
}
}
System.out.println();
}
}
static public void dfs(int i,int j) {
if(i<0||i>=n||j<0||j>=n) return;
if(arr[i][j]==0) {
arr[i][j]=3;
for(int x=0;x<4;x++) {
int ni=i+dx[x];
int nj=j+dy[x];
dfs(ni, nj);
}
}
}
}
P1135 奇怪的电梯
题目背景
感谢 @yummy 提供的一些数据。
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i i i 层楼( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N)上有一个数字 K i K_i Ki( 0 ≤ K i ≤ N 0 \le K_i \le N 0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3 , 3 , 1 , 2 , 5 3, 3, 1, 2, 5 3,3,1,2,5 代表了 K i K_i Ki( K 1 = 3 K_1=3 K1=3, K 2 = 3 K_2=3 K2=3,......),从 1 1 1 楼开始。在 1 1 1 楼,按"上"可以到 4 4 4 楼,按"下"是不起作用的,因为没有 − 2 -2 −2 楼。那么,从 A A A 楼到 B B B 楼至少要按几次按钮呢?
输入格式
共二行。
第一行为三个用空格隔开的正整数,表示 N , A , B N, A, B N,A,B( 1 ≤ N ≤ 200 1 \le N \le 200 1≤N≤200, 1 ≤ A , B ≤ N 1 \le A, B \le N 1≤A,B≤N)。
第二行为 N N N 个用空格隔开的非负整数,表示 K i K_i Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出 -1。
输入输出样例 #1
输入 #1
5 1 5
3 3 1 2 5
输出 #1
3
说明/提示
对于 100 % 100 \% 100% 的数据, 1 ≤ N ≤ 200 1 \le N \le 200 1≤N≤200, 1 ≤ A , B ≤ N 1 \le A, B \le N 1≤A,B≤N, 0 ≤ K i ≤ N 0 \le K_i \le N 0≤Ki≤N。
本题共 16 16 16 个测试点,前 15 15 15 个每个测试点 6 6 6 分,最后一个测试点 10 10 10 分。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
int n=Integer.parseInt(stringTokenizer.nextToken());
int a=Integer.parseInt(stringTokenizer.nextToken());
int b=Integer.parseInt(stringTokenizer.nextToken());
stringTokenizer=new StringTokenizer(br.readLine());
PrintWriter pw=new PrintWriter(System.out,true);
int []k=new int[n+5];
int []step=new int[n+5];
for(int i=1;i<=n;i++) {
k[i]=Integer.parseInt(stringTokenizer.nextToken());
}
Queue<Integer> queue=new LinkedList<>();
step[a]=0;
queue.add(a);
int []d= {1,-1};
while(!queue.isEmpty()) {
int now=queue.poll();
if(now==b) {
pw.println(step[b]);
pw.close();
return;
}
for(int i:d) {
int next=now+k[now]*i;
if(next>=1&&next<=n&&step[next]==0) {
step[next]=step[now]+1;
queue.add(next);
}
}
}
pw.println(-1);
pw.close();
}
}
P9241 [蓝桥杯 2023 省 B] 飞机降落
题目描述
N N N 架飞机准备降落到某个只有一条跑道的机场。其中第 i i i 架飞机在 T i T_{i} Ti 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 D i D_{i} Di 个单位时间,即它最早可以于 T i T_{i} Ti 时刻开始降落,最晩可以于 T i + D i T_{i}+D_{i} Ti+Di 时刻开始降落。降落过程需要 L i L_{i} Li 个单位时间。
一架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。
请你判断 N N N 架飞机是否可以全部安全降落。
输入格式
输入包含多组数据。
第一行包含一个整数 T T T,代表测试数据的组数。
对于每组数据,第一行包含一个整数 N N N。
以下 N N N 行,每行包含三个整数 T i , D i , L i T_{i},D_{i},L_{i} Ti,Di,Li。
输出格式
对于每组数据,输出 YES 或者 NO,代表是否可以全部安全降落。
输入输出样例 #1
输入 #1
2
3
0 100 10
10 10 10
0 2 20
3
0 10 20
10 10 20
20 10 20
输出 #1
YES
NO
说明/提示
【样例说明】
对于第一组数据,可以安排第 3 架飞机于 0 时刻开始降落,20 时刻完成降落。安排第 2 架飞机于 20 时刻开始降落,30 时刻完成降落。安排第 1 架飞机于 30 时刻开始降落,40 时刻完成降落。
对于第二组数据,无论如何安排,都会有飞机不能及时降落。
【评测用例规模与约定】
对于 30 % 30 \% 30% 的数据, N ≤ 2 N \leq 2 N≤2。
对于 100 % 100 \% 100% 的数据, 1 ≤ T ≤ 10 1 \leq T \leq 10 1≤T≤10, 1 ≤ N ≤ 10 1 \leq N \leq 10 1≤N≤10, 0 ≤ T i , D i , L i ≤ 10 5 0 \leq T_{i},D_{i},L_{i} \leq 10^{5} 0≤Ti,Di,Li≤105。
蓝桥杯 2023 省赛 B 组 D 题。
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int [][]arr;
static int n;
static boolean []vis;
static boolean ok;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int t=Integer.parseInt(br.readLine());
while(t-->0) {
n=Integer.parseInt(br.readLine());
vis=new boolean[n+2];
arr=new int[n+4][3];
for(int i=0;i<n;i++) {
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
arr[i][0]=Integer.parseInt(stringTokenizer.nextToken());
arr[i][1]=Integer.parseInt(stringTokenizer.nextToken());
arr[i][2]=Integer.parseInt(stringTokenizer.nextToken());
}
dfs(0, 0);
if(ok) System.out.println("YES");
else System.out.println("NO");
ok=false;
}
}
static public void dfs(int a,int b) {
if(b==n) {
ok=true;
return;
}
int now=a;
for(int i=0;i<n;i++) {
if(vis[i]) continue;
int t=arr[i][0];
int d=arr[i][1];
int l=arr[i][2];
int max=Math.max(now, t);
if(max<=t+d) {
vis[i]=true;
dfs(max+l, b+1);
vis[i]=false;
}
}
}
}
P1036 [NOIP 2002 普及组] 选数
题目描述
已知 n n n 个整数 x 1 , x 2 , ⋯ , x n x_1,x_2,\cdots,x_n x1,x2,⋯,xn,以及 1 1 1 个整数 k k k( k < n k<n k<n)。从 n n n 个整数中任选 k k k 个整数相加,可分别得到一系列的和。例如当 n = 4 n=4 n=4, k = 3 k=3 k=3, 4 4 4 个整数分别为 3 , 7 , 12 , 19 3,7,12,19 3,7,12,19 时,可得全部的组合与它们的和为:
3 + 7 + 12 = 22 3+7+12=22 3+7+12=22
3 + 7 + 19 = 29 3+7+19=29 3+7+19=29
7 + 12 + 19 = 38 7+12+19=38 7+12+19=38
3 + 12 + 19 = 34 3+12+19=34 3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数: 3 + 7 + 19 = 29 3+7+19=29 3+7+19=29。
输入格式
第一行两个空格隔开的整数 n , k n,k n,k( 1 ≤ n ≤ 20 1 \le n \le 20 1≤n≤20, k < n k<n k<n)。
第二行 n n n 个整数,分别为 x 1 , x 2 , ⋯ , x n x_1,x_2,\cdots,x_n x1,x2,⋯,xn( 1 ≤ x i ≤ 5 × 10 6 1 \le x_i \le 5\times 10^6 1≤xi≤5×106)。
输出格式
输出一个整数,表示种类数。
输入输出样例 #1
输入 #1
4 3
3 7 12 19
输出 #1
1
说明/提示
【题目来源】
NOIP 2002 普及组第二题
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int n,k,ans;
static int []arr;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
n=Integer.parseInt(stringTokenizer.nextToken());
k=Integer.parseInt(stringTokenizer.nextToken());
arr=new int[n+5];
ans=0;
stringTokenizer=new StringTokenizer(br.readLine());
for(int i=0;i<n;i++) {
arr[i]=Integer.parseInt(stringTokenizer.nextToken());
}
dfs(0, 0,0);
System.out.println(ans);
}
static public boolean isPrime(int a) {
if(a<2) {
return false;
}
if(a==2) return true;
if(a%2==0) return false;
for(int i=3;i*i<=a;i+=2) {
if(a%i==0) return false;
}
return true;
}
static public void dfs(int a,int b,int sum) {
if(b==k) {
if(isPrime(sum)) ans++;
return;
}
if (n - a < k - b) return;
for(int i=a;i<n;i++) {
b+=1;
sum+=arr[i];
dfs(i+1,b,sum);
sum-=arr[i];
b--;
}
}
}

P1473 [USACO2.3] 零的数列 Zero Sum
题目描述
请考虑一个由 1 1 1 到 N N N 的数字组成的递增数列: 1 , 2 , 3 , ... , N 1, 2, 3, \ldots, N 1,2,3,...,N。
现在请在数列中插入 + 表示加,或者 - 表示减, (空格) 表示空白(例如 1-2 3 就等于 1-23),来将每一对数字组合在一起(请不要在第一个数字前插入符号)。
计算该表达式的结果并判断其值是否为 0 0 0。 请你写一个程序找出所有产生和为零的长度为N的数列。
输入格式
单独的一行表示整数 N N N( 3 ≤ N ≤ 9 3 \leq N \leq 9 3≤N≤9)。
输出格式
按照 ASCI I码的顺序,输出所有在每对数字间插入 +,-, (空格) 后能得到结果为零的数列。
输入输出样例 #1
输入 #1
7
输出 #1
1+2-3+4-5-6+7
1+2-3-4+5+6-7
1-2 3+4+5+6+7
1-2 3-4 5+6 7
1-2+3+4-5+6-7
1-2-3-4-5+6+7
说明/提示
翻译来自NOCOW
USACO 2.3
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int n;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(br.readLine());
dfs(2, 1, "1",1);
}
static public void dfs(int index,int sum,String s,int last) {
if(index>n) {
if(sum==0) {
System.out.println(s);
}
return;
}
int newNum=last*10+(last>0?index:-index);
dfs(index+1,sum-last+newNum,s+" "+index,newNum);
dfs(index+1,sum+index,s+"+"+index,index);
dfs(index+1,sum-index,s+"-"+index,-index);
}
}
P2040 打开所有的灯
题目背景
pmshz 在玩一个益 (ruo) 智 (zhi) 的小游戏,目的是打开九盏灯所有的灯,这样的游戏难倒了 pmshz......
题目描述
这个灯很奇 (fan) 怪 (ren),点一下就会将这个灯和其周围四盏灯的开关状态全部改变。现在你的任务就是就是告诉 pmshz 要全部打开这些灯。
例如
plain
0 1 1
1 0 0
1 0 1
点一下最中间的灯 ( 2 , 2 ) (2,2) (2,2) 就变成了
plain
0 0 1
0 1 1
1 1 1
再点一下左上角的灯 ( 1 , 1 ) (1,1) (1,1) 就变成了
plain
1 1 1
1 1 1
1 1 1
达成目标。
最少需要 2 2 2 步。
输入格式
9 9 9 个数字,以 3 × 3 3\times3 3×3 的格式输入,每两个数字中间只有一个空格,表示灯初始的开关状态。( 0 0 0 表示关, 1 1 1 表示开)
输出格式
一个整数,表示最少打开所有灯所需要的步数。
输入输出样例 #1
输入 #1
0 1 1
1 0 0
1 0 1
输出 #1
2
说明/提示
这个题水不水,就看你怎么考虑了......
代码
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
import java.security.spec.DSAGenParameterSpec;
public class Main {
static int [][]arr=new int[5][5];
static int min=Integer.MAX_VALUE;
static int []dx= {-1,0,1,0,0};
static int []dy= {0,1,0,-1,0};
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
for(int i=0;i<3;i++) {
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
arr[i][0]=Integer.parseInt(stringTokenizer.nextToken());
arr[i][1]=Integer.parseInt(stringTokenizer.nextToken());
arr[i][2]=Integer.parseInt(stringTokenizer.nextToken());
}
dfs(0, 0);
System.out.println(min);
}
static public void dfs(int dex,int step) {
if(step>=min) return;
if(dex>=9) {
if(checkIn()) {
min=step;
}
return;
}
dfs(dex+1, step);
flap(dex);
dfs(dex+1, step+1);
flap(dex);
}
static public boolean checkIn() {
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
if(arr[i][j]==0) {
return false;
}
}
}
return true;
}
static public void flap(int dex) {
int x=dex/3;
int y=dex%3;
for(int i=0;i<5;i++) {
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=0&&ny>=0&&nx<3&&ny<3) {
arr[nx][ny]^=1;
}
}
}
}
P1219 [USACO1.5] 八皇后 Checker Challenge
题目描述
一个如下的 6 × 6 6 \times 6 6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2 4 6 1 3 5 2\ 4\ 6\ 1\ 3\ 5 2 4 6 1 3 5 来描述,第 i i i 个数字表示在第 i i i 行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6 1\ 2\ 3\ 4\ 5\ 6 1 2 3 4 5 6
列号 2 4 6 1 3 5 2\ 4\ 6\ 1\ 3\ 5 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 3 3 个解。最后一行是解的总个数。
输入格式
一行一个正整数 n n n,表示棋盘是 n × n n \times n n×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例 #1
输入 #1
6
输出 #1
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
说明/提示
【数据范围】
对于 100 % 100\% 100% 的数据, 6 ≤ n ≤ 13 6 \le n \le 13 6≤n≤13。
题目翻译来自NOCOW。
USACO Training Section 1.5
代码
java
import java.util.*;
import java.io.*;
public class Main {
static boolean []col;
static boolean []dl;
static boolean []dr;
static int n,count=0;
static int []ans;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(br.readLine());
col=new boolean[n+1];
dl=new boolean[2*n+1];
dr=new boolean[2*n+1];
ans=new int[n+1];
dfs(1);
System.out.println(count);
}
static public void dfs(int row) {
if(row>n) {
count++;
if(count<=3) {
for(int i=1;i<=n;i++) {
System.out.print(ans[i]+" ");
}
System.out.println();
}
return ;
}
for(int i=1;i<=n;i++) {
int l=row-i+n;
int r=row+i;
if(!col[i]&&!dl[l]&&!dr[r]) {
col[i]=true;
dl[l]=true;
dr[r]=true;
ans[row]=i;
dfs(row+1);
col[i]=false;
dl[l]=false;
dr[r]=false;
ans[row]=0;
}
}
}
}
B4158 [BCSP-X 2024 12 月小学高年级组] 质数补全
题目描述
Alice 在纸条上写了一个质数,第二天再看时发现有些地方污损看不清了。
- 在大于 1 1 1 的自然数中,除了 1 1 1 和它本身以外不再有其他因数的自然数称为质数
请你帮助 Alice 补全这个质数,若有多解输出数值最小的,若无解输出 − 1 -1 −1。
例如纸条上的数字为 1 ∗ \tt{1*} 1∗( ∗ \tt{*} ∗ 代表看不清的地方),那么这个质数有可能为 11 , 13 , 17 , 19 11, 13, 17, 19 11,13,17,19,其中最小的为 11 11 11。
输入格式
第一行 1 1 1 个整数 t t t,代表有 t t t 组数据。
接下来 t t t 行,每行 1 1 1 个字符串 s s s 代表 Alice 的数字,仅包含数字或者 ∗ \tt{*} ∗,并且保证首位不是 ∗ \tt{*} ∗ 或者 0 0 0。
输出格式
输出 t t t 行,每行 1 1 1 个整数代表最小可能的质数,或者 − 1 -1 −1 代表无解。
输入输出样例 #1
输入 #1
10
1*
3**
7**
83*7
2262
6**1
29*7
889*
777*
225*
输出 #1
11
307
701
8317
-1
6011
2917
8893
-1
2251
输入输出样例 #2
输入 #2
10
4039***
2***5*5
4099961
25**757
7***0**
1***00*
41811*9
6***0*7
8***1**
6561*59
输出 #2
4039019
-1
4099961
2509757
7000003
1000003
4181129
6000047
8000101
6561259
说明/提示
样例 3-6
参考附件中的样例。
数据范围
∣ s ∣ |s| ∣s∣ 代表 s s s 串的长度,对于所有数据, 1 ≤ t ≤ 10 , 1 ≤ ∣ s ∣ ≤ 7 1 \leq t \leq 10, 1 \leq |s| \leq 7 1≤t≤10,1≤∣s∣≤7, s s s 中仅包含数字或者 ∗ \tt{*} ∗,并且保证首位不是 ∗ \tt{*} ∗ 或者 0 0 0。
本题采用捆绑测试,你必须通过子任务中的所有数据点以及其依赖的子任务,才能获得子任务对应的分数。
| 子任务编号 | 分值 | ∣ s ∣ \mid s\mid ∣s∣ | 特殊性质 | 子任务依赖 |
|---|---|---|---|---|
| 1 1 1 | 35 35 35 | ≤ 7 \leq 7 ≤7 | s s s 中没有 ∗ \tt{*} ∗ | |
| 2 2 2 | 30 30 30 | ≤ 4 \leq 4 ≤4 | ||
| 3 3 3 | 24 24 24 | ≤ 7 \leq 7 ≤7 | s s s 中至多包含 1 1 1 个 ∗ \tt{*} ∗ | 1 1 1 |
| 4 4 4 | 11 11 11 | ≤ 7 \leq 7 ≤7 | 1 , 2 , 3 1,2,3 1,2,3 |
java
import java.util.*;
import java.io.*;
public class Main {
static String s;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int t=Integer.parseInt(br.readLine());
while(t-->0) {
s=br.readLine();
if(!dfs(0, 0L)) {
System.out.println(-1);
}
}
}
static public boolean isPrime(long n) {
if(n<2) return false;
if(n==2) return true;
if(n%2==0) return false;
for(int i=3;i*i<=n;i+=2) {
if(n%i==0) return false;
}
return true;
}
static public boolean dfs(int i,long n) {
if(i>=s.length()) {
if(isPrime(n)) {
System.out.println(n);
return true;
}
return false;
}
if(s.charAt(i)=='*') {
for(int j=0;j<=9;j++) {
n=n*10+j;
if(dfs(i+1, n)) {
return true;
}else {
n=(n-j)/10;
}
}
}else {
n=n*10+(s.charAt(i)-'0');
if(dfs(i+1, n)) {
return true;
}else {
n=(n-s.charAt(i))/10;
}
}
return false;
}
}
P10386 [蓝桥杯 2024 省 A] 五子棋对弈
题目描述
"在五子棋的对弈中,友谊的小船说翻就翻?" 不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着 "友谊第一,比赛第二" 的宗旨,决定在一块 5 × 5 5 × 5 5×5 的棋盘上,用黑白两色的棋子来决出胜负。但他们又都不忍心让对方失落,于是决定用一场和棋(平局) 作为彼此友谊的见证。
比赛遵循以下规则:
- 棋盘规模:比赛在一个 5 × 5 5 × 5 5×5 的方格棋盘上进行,共有 25 25 25 个格子供下棋使用。
- 棋子类型:两种棋子,黑棋与白棋,代表双方。小蓝持白棋,小桥持黑棋。
- 先手规则:白棋(小蓝)具有先手优势,即在棋盘空白时率先落子(下棋)。
- 轮流落子:玩家们交替在棋盘上放置各自的棋子,每次仅放置一枚。
- 胜利条件:率先在横线、竖线或斜线上形成连续的五个同色棋子的一方获胜。
- 平局条件:当所有 25 25 25 个棋盘格都被下满棋子,而未决出胜负时,游戏以平局告终。
在这一设定下,小蓝和小桥想知道,有多少种不同的棋局情况(终局不同看成不同情况,终局相同而落子顺序不同看成同一种情况),既确保棋盘下满又保证比赛结果为平局。
输入格式
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
输出格式
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
代码
java
package text;
import java.util.*;
import java.io.*;
public class test1 {
static int [][]arr=new int[6][6];
static int count=0;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
dfs(0, 0, 0);
System.out.println(count);
}
static public void dfs(int index,int white,int black) {
if(index>=25) {
if(white==13&&black==12) {
if(check()) {
count++;
}
}
return;
}
int x=index/5;
int y=index%5;
arr[x][y]=0;
dfs(index+1,white+1,black);
arr[x][y]=1;
dfs(index+1,white,black+1);
}
static public boolean check() {
for(int i=0;i<5;i++) {
if(arr[i][0]==arr[i][1]&&arr[i][2]==arr[i][1]&&arr[i][2]==arr[i][3]&&arr[i][3]==arr[i][4]) {
return false;
}
}
for(int i=0;i<5;i++) {
if(arr[0][i]==arr[1][i]&&arr[2][i]==arr[1][i]&&arr[2][i]==arr[3][i]&&arr[3][i]==arr[4][i]) {
return false;
}
}
if(arr[0][0]==arr[1][1]&&arr[2][2]==arr[1][1]&&arr[2][2]==arr[3][3]&&arr[3][3]==arr[4][4]) {
return false;
}
if(arr[0][4]==arr[1][3]&&arr[2][2]==arr[1][3]&&arr[2][2]==arr[3][1]&&arr[3][1]==arr[4][0]) {
return false;
}
return true;
}
}
P8786 [蓝桥杯 2022 省 B] 李白打酒加强版
题目描述
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒 2 2 2 斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 N N N 次,遇到花 M M M 次。已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:壶里没酒( 0 0 0 斗)时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。
输入格式
第一行包含两个整数 N N N 和 M M M。
输出格式
输出一个整数表示答案。由于答案可能很大,输出模 1000000007 1000000007 1000000007(即 10 9 + 7 10^9+7 109+7)的结果。
输入输出样例 #1
输入 #1
5 10
输出 #1
14
说明/提示
【样例说明】
如果我们用 0 代表遇到花,1 代表遇到店, 14 14 14 种顺序如下:
plain
010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100
【评测用例规模与约定】
对于 40 % 40 \% 40% 的评测用例: 1 ≤ N , M ≤ 10 1 \leq N, M \leq 10 1≤N,M≤10。
对于 100 % 100 \% 100% 的评测用例: 1 ≤ N , M ≤ 100 1 \leq N, M \leq 100 1≤N,M≤100。
蓝桥杯 2022 省赛 B 组 I 题。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
int n=Integer.parseInt(stringTokenizer.nextToken());
int m=Integer.parseInt(stringTokenizer.nextToken());
int [][][]dp=new int[n+5][m+5][105];
dp[0][0][2]=1;
for(int i=0;i<=n;i++) {
for(int j=0;j<=m-1;j++) {
if(i==0&&j==0) continue;
for(int k=0;k<=100;k++) {
if(k%2==0&&i!=0) dp[i][j][k]+=dp[i-1][j][k/2];
if(j!=0)dp[i][j][k]+=dp[i][j-1][k+1];
dp[i][j][k]%=1000000007;
}
}
}
System.out.println(dp[n][m-1][1]);
}
}
P12344 [蓝桥杯 2025 省 B/Python B 第二场] 破解信息
题目描述
在遥远的未来,星际旅行已经成为常态。宇航员小蓝在一次探险任务中,意外发现了一个古老的太空遗迹。遗迹中存放着一个数据存储器,里面记录着一段加密的信息。经过初步分析,小蓝发现这段信息可以被表示为一个字符串 S S S,而解密的关键,在于找出 S S S 中字典序最大的回文子序列。
- 子序列 :指从原字符串中抽取若干个字符(可以不连续),按照它们在原字符串中的相对顺序排列所形成的新序列。例如,对于字符串
abc,其子序列包括a、b、c、ab、ac、bc和abc。 - 字典序 :指字符串按照字典中的排序规则比较大小的方式。对于两个字符串,从左到右逐字符比较,先出现较大字符的字符串字典序更大;若比较到某个字符串结束仍未找到不同的字符,则较短的字符串字典序较小。例如,
abc<abd,而ab<abc。
现在,请你从字符串 S S S 中,找出字典序最大的回文子序列,帮助小蓝解开这段来自星际文明的信息。
输入格式
输入一行包含一个字符串 S S S,表示加密的信息。
输出格式
输出一行包含一个字符串,表示 S S S 中字典序最大的回文子序列。
输入输出样例 #1
输入 #1
abcd
输出 #1
d
输入输出样例 #2
输入 #2
abab
输出 #2
bb
说明/提示
评测用例规模与约定
- 对于 30 % 30\% 30% 的评测用例, 1 ≤ ∣ S ∣ ≤ 300 1 \leq |S| \leq 300 1≤∣S∣≤300,其中 ∣ S ∣ |S| ∣S∣ 表示字符串 S S S 的长度;
- 对于所有评测用例, 1 ≤ ∣ S ∣ ≤ 10 5 1 \leq |S| \leq 10^5 1≤∣S∣≤105, S S S 中只包含小写英文字母。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String strings=br.readLine();
char max='a';
for(int i=0;i<strings.length();i++) {
if(strings.charAt(i)>max) {
max=strings.charAt(i);
}
}
StringBuilder stringBuilder=new StringBuilder();
for(int i=0;i<strings.length();i++) {
if(strings.charAt(i)==max) {
stringBuilder.append(max);
}
}
System.out.println(stringBuilder);
}
}
P12342 [蓝桥杯 2025 省 B/Python B 第二场] 数列差分
题目描述
小蓝有两个长度均为 n n n 的数列 A = { a 1 , a 2 , ⋯ , a n } A=\{a_1, a_2, \cdots, a_n\} A={a1,a2,⋯,an} 和 B = { b 1 , b 2 , ⋯ , b n } B=\{b_1, b_2, \cdots, b_n\} B={b1,b2,⋯,bn},将两个数列作差定义为 C = A − B = { c 1 = a 1 − b 1 , c 2 = a 2 − b 2 , ⋯ , c n = a n − b n } C=A-B=\{c_1=a_1-b_1, c_2=a_2-b_2, \cdots, c_n=a_n-b_n\} C=A−B={c1=a1−b1,c2=a2−b2,⋯,cn=an−bn}。小蓝将对数列 B B B 进行若干次操作,每次操作可以将数列 B B B 中的任意一个数更改为任意一个整数。在进行完所有操作后,小蓝可以按任意顺序将数列 B B B 重排,之后再计算数列 C C C。小蓝想知道,最少操作多少次可以使得数列 C C C 中的所有数都为正整数。
输入格式
输入的第一行包含一个正整数 n n n;
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an,相邻整数之间使用一个空格分隔。
第三行包含 n n n 个整数 b 1 , b 2 , ⋯ , b n b_1, b_2, \cdots, b_n b1,b2,⋯,bn,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
输入输出样例 #1
输入 #1
4
22 31 12 14
3 19 27 44
输出 #1
1
说明/提示
样例说明
其中一种方案:将 44 44 44 改为 0 0 0,重新排列 B B B 为 { 19 , 27 , 3 , 0 } \{19, 27, 3, 0\} {19,27,3,0},使得数列 C = { 3 , 4 , 9 , 14 } C=\{3, 4, 9, 14\} C={3,4,9,14} 均为正整数。
评测用例规模与约定
- 对于 30 % 30\% 30% 的评测用例, n ≤ 10 n \leq 10 n≤10;
- 对于所有评测用例, 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105, − 10 9 ≤ a i ≤ 10 9 -10^9 \leq a_i \leq 10^9 −109≤ai≤109, − 10 9 ≤ b i ≤ 10 9 -10^9 \leq b_i \leq 10^9 −109≤bi≤109。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
int []a=new int[n];
int []b=new int[n];
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
for(int i=0;i<n;i++) {
a[i]=Integer.parseInt(stringTokenizer.nextToken());
}
stringTokenizer=new StringTokenizer(br.readLine());
for(int i=0;i<n;i++) {
b[i]=Integer.parseInt(stringTokenizer.nextToken());
}
int i=0;
int j=0;
int count=0;
Arrays.sort(a);
Arrays.sort(b);
while(i<n&&j<n) {
if(a[i]>b[j]) {
i++;
j++;
}else {
i++;
count++;
}
}
System.out.println(count);
}
}
二维数组排序

想按照第一列的顺序进行排序就[0],否则的话按照第二列就[1],如果是从小到大的话就(o1, o2) ->o1 - o2),反之,则从大到小
P9242 [蓝桥杯 2023 省 B] 接龙数列
题目描述
对于一个长度为 K K K 的整数数列: A 1 , A 2 , ... , A K A_{1},A_{2},\ldots,A_{K} A1,A2,...,AK,我们称之为接龙数列当且仅当 A i A_{i} Ai 的首位数字恰好等于 A i − 1 A_{i-1} Ai−1 的末位数字( 2 ≤ i ≤ K 2 \leq i \leq K 2≤i≤K)。
例如 12 , 23 , 35 , 56 , 61 , 11 12,23,35,56,61,11 12,23,35,56,61,11 是接龙数列; 12 , 23 , 34 , 56 12,23,34,56 12,23,34,56 不是接龙数列,因为 56 56 56 的首位数字不等于 34 34 34 的末位数字。所有长度为 1 1 1 的整数数列都是接龙数列。
现在给定一个长度为 N N N 的数列 A 1 , A 2 , ... , A N A_{1},A_{2},\ldots,A_{N} A1,A2,...,AN,请你计算最少从中删除多少 个数,可以使剩下的序列是接龙序列?
输入格式
第一行包含一个整数 N N N。
第二行包含 N N N 个整数 A 1 , A 2 , ... , A N A_{1},A_{2},\ldots,A_{N} A1,A2,...,AN。
输出格式
一个整数代表答案。
输入输出样例 #1
输入 #1
5
11 121 22 12 2023
输出 #1
1
说明/提示
【样例说明】
删除 22 22 22,剩余 11 , 121 , 12 , 2023 11,121,12,2023 11,121,12,2023 是接龙数列。
【评测用例规模与约定】
对于 20 % 20 \% 20% 的数据, 1 ≤ N ≤ 20 1 \leq N \leq 20 1≤N≤20。
对于 50 % 50 \% 50% 的数据, 1 ≤ N ≤ 10 4 1 \leq N \leq 10^4 1≤N≤104。
对于 100 % 100 \% 100% 的数据, 1 ≤ N ≤ 10 5 1 \leq N \leq 10^{5} 1≤N≤105, 1 ≤ A i ≤ 10 9 1 \leq A_{i} \leq 10^{9} 1≤Ai≤109。所有 A i A_{i} Ai 保证不包含前导 0。
蓝桥杯 2023 省赛 B 组 E 题。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
int []a=new int[n];
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
for(int i=0;i<n;i++) {
a[i]=Integer.parseInt(stringTokenizer.nextToken());
}
int []dp=new int[10];
for(int i=0;i<n;i++) {
int first=a[i];
while(first>=10) {
first/=10;
}
int last=a[i]%10;
dp[last]=Math.max(dp[last], dp[first]+1);
}
int max=Integer.MIN_VALUE;
for(int i=0;i<10;i++) {
max=Math.max(max, dp[i]);
}
System.out.println(n-max);
}
}
P10387 [蓝桥杯 2024 省 A] 训练士兵
题目描述
在蓝桥王国中,有 n n n 名士兵,这些士兵需要接受一系列特殊的训练,以提升他们的战斗技能。对于第 i i i 名士兵来说,进行一次训练所需的成本为 p i p_i pi 枚金币,而要想成为顶尖战士,他至少需要进行 c i c_i ci 次训练。
为了确保训练的高效性,王国推出了一种组团训练的方案。该方案包含每位士兵所需的一次训练,且总共只需支付 S S S 枚金币(组团训练方案可以多次购买,即士兵可以进行多次组团训练)。
作为训练指挥官,请你计算出最少需要花费多少金币,才能使得所有的士兵都成为顶尖战士?
输入格式
输入的第一行包含两个整数 n n n 和 S ,用一个空格分隔,表示士兵的数量和进行一次组团训练所需的金币数。
接下来的 n n n 行,每行包含两个整数 p i p_i pi 和 c i c_i ci,用一个空格分隔,表示第 i i i 名士兵进行一次训练的金币成本和要成为顶尖战士所需的训练次数。
输出格式
输出一行包含一个整数,表示使所有士兵成为顶尖战士所需的最少金币数。
输入输出样例 #1
输入 #1
3 6
5 2
2 4
3 2
输出 #1
16
说明/提示
花费金币最少的训练方式为:进行 2 2 2 次组团训练,花费 2 × 6 = 12 2 × 6 = 12 2×6=12 枚金币,此时士兵 1 , 3 1, 3 1,3 已成为顶尖战士;再花费 4 4 4 枚金币,让士兵 2 2 2 进行两次训练,成为顶尖战士。总花费为 12 + 4 = 16 12 + 4 = 16 12+4=16。
对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 10 3 , 1 ≤ p i , c i ≤ 10 5 , 1 ≤ S ≤ 10 7 1 ≤ n ≤ 10^3,1 ≤ p_i , c_i ≤ 10^5,1 ≤ S ≤ 10^7 1≤n≤103,1≤pi,ci≤105,1≤S≤107。
对于所有评测用例, 1 ≤ n ≤ 10 5 , 1 ≤ p i , c i ≤ 10 6 , 1 ≤ S ≤ 10 10 1 ≤ n ≤ 10^5,1 ≤ p_i , c_i ≤ 10^6,1 ≤ S ≤ 10^{10} 1≤n≤105,1≤pi,ci≤106,1≤S≤1010。
代码
java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
int n=Integer.parseInt(stringTokenizer.nextToken());
long s=Long.parseLong(stringTokenizer.nextToken());
int [][]a=new int[n][2];
int max=Integer.MIN_VALUE;
long sum=0;
for(int i=0;i<n;i++) {
stringTokenizer=new StringTokenizer(br.readLine());
a[i][0]=Integer.parseInt(stringTokenizer.nextToken());
a[i][1]=Integer.parseInt(stringTokenizer.nextToken());
max=Math.max(max, a[i][1]);
sum+=(long)a[i][0];
}
Arrays.sort(a,(o1,o2)->o1[1]-o2[1]);
int ji=0;
long m=0;
for(int i=0;i<n;i++) {
if(sum>s) {
ji=a[i][1];
sum-=a[i][0];
continue;
}
m+=(long)a[i][0]*(a[i][1]-ji);
}
m+=s*ji;
System.out.println(m);
}
}
P1182 数列分段 Section II
题目描述
对于给定的一个长度为 N N N 的正整数数列 A 1 ∼ N A_{1\sim N} A1∼N,现要将其分成 M M M( M ≤ N M\leq N M≤N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列 4 2 4 5 1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 要分成 3 3 3 段。
将其如下分段:
4 2 \] \[ 4 5 \] \[ 1 \] \[4\\ 2\]\[4\\ 5\]\[1\] \[4 2\]\[4 5\]\[1
第一段和为 6 6 6,第 2 2 2 段和为 9 9 9,第 3 3 3 段和为 1 1 1,和最大值为 9 9 9。
将其如下分段:
4 \] \[ 2 4 \] \[ 5 1 \] \[4\]\[2\\ 4\]\[5\\ 1\] \[4\]\[2 4\]\[5 1
第一段和为 4 4 4,第 2 2 2 段和为 6 6 6,第 3 3 3 段和为 6 6 6,和最大值为 6 6 6。
并且无论如何分段,最大值不会小于 6 6 6。
所以可以得到要将数列 4 2 4 5 1 4\ 2\ 4\ 5\ 1 4 2 4 5 1 要分成 3 3 3 段,每段和的最大值最小为 6 6 6。
输入格式
第 1 1 1 行包含两个正整数 N , M N,M N,M。
第 2 2 2 行包含 N N N 个空格隔开的非负整数 A i A_i Ai,含义如题目所述。
输出格式
一个正整数,即每段和最大值最小为多少。
输入输出样例 #1
输入 #1
5 3
4 2 4 5 1
输出 #1
6
说明/提示
对于 20 % 20\% 20% 的数据, N ≤ 10 N\leq 10 N≤10。
对于 40 % 40\% 40% 的数据, N ≤ 1000 N\leq 1000 N≤1000。
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 10 5 1\leq N\leq 10^5 1≤N≤105, M ≤ N M\leq N M≤N, A i < 10 8 A_i < 10^8 Ai<108, 答案不超过 10 9 10^9 109。
代码
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
public class Main {
static int m;
static int []a;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
int n=Integer.parseInt(stringTokenizer.nextToken());
m=Integer.parseInt(stringTokenizer.nextToken());
a=new int[n];
long right=0;
long left=Integer.MIN_VALUE;
long ans=0;
stringTokenizer=new StringTokenizer(br.readLine());
for(int i=0;i<n;i++) {
a[i]=Integer.parseInt(stringTokenizer.nextToken());
left=Math.max(left, a[i]);
right+=a[i];
}
while(left<=right) {
long mid=(left+right)/2;
if(check(mid)) {
ans=mid;
right=mid-1;
}else {
left=mid+1;
}
}
System.out.println(ans);
}
static boolean check(long mid) {
int sum=0;
int count=1;
for(int num:a) {
if(sum+num>mid) {
sum=num;
count++;
if(count>m) {
return false;
}
}else {
sum+=num;
}
}
return count<=m;
}
}
P2440 木材加工
题目背景
要保护环境。
题目描述
木材厂有 n n n 根原木,现在想把这些木头切割成 k k k 段长度均 为 l l l 的小段木头(木头有可能有剩余)。
当然,我们希望得到的小段木头越长越好,请求出 l l l 的最大值。
木头长度的单位是 cm \text{cm} cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。
例如有两根原木长度分别为 11 11 11 和 21 21 21,要求切割成等长的 6 6 6 段,很明显能切割出来的小段木头长度最长为 5 5 5。
输入格式
第一行是两个正整数 n , k n,k n,k,分别表示原木的数量,需要得到的小段的数量。
接下来 n n n 行,每行一个正整数 L i L_i Li,表示一根原木的长度。
输出格式
仅一行,即 l l l 的最大值。
如果连 1cm \text{1cm} 1cm 长的小段都切不出来,输出 0。
输入输出样例 #1
输入 #1
3 7
232
124
456
输出 #1
114
说明/提示
数据规模与约定
对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 10 5 1\le n\le 10^5 1≤n≤105, 1 ≤ k ≤ 10 8 1\le k\le 10^8 1≤k≤108, 1 ≤ L i ≤ 10 8 ( i ∈ [ 1 , n ] ) 1\le L_i\le 10^8(i\in[1,n]) 1≤Li≤108(i∈[1,n])。
代码
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
public class Main {
static int k,n;
static int []a;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
n=Integer.parseInt(stringTokenizer.nextToken());
k=Integer.parseInt(stringTokenizer.nextToken());
a=new int[n+5];
int right=1;
for(int i=0;i<n;i++) {
a[i]=Integer.parseInt(br.readLine());
right=Math.max(right, a[i]);
}
int left=1;
int ans=0;
while(left<=right) {
int mid=(left+right)/2;
if(check(mid)) {
right=mid-1;
}else {
left=mid+1;
ans=mid;
}
}
System.out.println(ans);
}
static boolean check(long mid) {
long count=0;
for(int i:a) {
count+=((long)i/mid);
if(count >=k) return false;
}
return count<k;
}
}
P10909 [蓝桥杯 2024 国 B] 立定跳远
题目描述
在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 n n n 个检查点 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots , a_n a1,a2,⋯,an 且 a i ≥ a i − 1 > 0 a_i \ge a_{i−1} > 0 ai≥ai−1>0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时,小明可以自行再增加 m m m 个检查点让自己跳得更轻松。
在运动会前,小明制定训练计划让自己单次跳跃的最远距离达到 L L L,并且学会一个爆发技能可以在运动会时使用一次,使用时可以在该次跳跃时的最远距离变为 2 L 2L 2L。小明想知道, L L L 的最小值是多少可以完成这个项目?
输入格式
输入共 2 2 2 行。
第一行为两个正整数 n , m n,m n,m。
第二行为 n n n 个由空格分开的正整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an。
输出格式
输出共 1 1 1 行,一个整数表示答案。
输入输出样例 #1
输入 #1
5 3
1 3 5 16 21
输出 #1
3
说明/提示
【样例说明】
增加检查点 10 , 13 , 19 10, 13, 19 10,13,19,因此每次跳跃距离为 1 , 2 , 2 , 5 , 3 , 3 , 3 , 2 1,2, 2, 5, 3, 3, 3, 2 1,2,2,5,3,3,3,2,在第三次跳跃时使用技能即可。
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例,保证 n ≤ 10 2 n \le 10^2 n≤102, m ≤ 10 3 m \le 10^3 m≤103, a i ≤ 10 3 a_i \le 10^3 ai≤103。
对于 100 % 100\% 100% 的评测用例,保证 2 ≤ n ≤ 10 5 2 \le n \le 10^5 2≤n≤105, m ≤ 10 8 m \le 10^8 m≤108, 0 < a i ≤ 10 8 0 < a_i \le 10^8 0<ai≤108。
代码
java
import java.util.*;
import java.io.*;
public class Main {
static int m,n;
static int []a;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
n=Integer.parseInt(stringTokenizer.nextToken());
m=Integer.parseInt(stringTokenizer.nextToken());
a=new int[n+5];
stringTokenizer=new StringTokenizer(br.readLine());
int max=0;
int min=0;
for(int i=0;i<n;i++) {
a[i]=Integer.parseInt(stringTokenizer.nextToken());
max=Math.max(max,a[i]);
min=Math.min(min,a[i]);
}
long right=((long)max+min+1)/2;
long left=0;
long ans=0;
while(left<=right) {
long mid=(left+right)/2;
if(check(mid)) {
right=mid-1;
ans=mid;
}else {
left=mid+1;
}
}
System.out.println(ans);
}
static boolean check(long mid) {
boolean used=false;
long count=0;
int pos=0;
for(int i=0;i<n;i++){
if(pos+mid>=a[i]){
pos=a[i];
continue;
}else if(pos+mid*2>=a[i]&&!used){
used=true;
pos=a[i];
continue;
}
count++;
if(count>m) return false;
pos+=mid;
i--;
}
return true;
}
}
P1048 [NOIP 2005 普及组] 采药
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:"孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。"
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 2 2 2 个整数 T T T( 1 ≤ T ≤ 1000 1 \le T \le 1000 1≤T≤1000)和 M M M( 1 ≤ M ≤ 100 1 \le M \le 100 1≤M≤100),用一个空格隔开, T T T 代表总共能够用来采药的时间, M M M 代表山洞里的草药的数目。
接下来的 M M M 行每行包括两个在 1 1 1 到 100 100 100 之间(包括 1 1 1 和 100 100 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入输出样例 #1
输入 #1
70 3
71 100
69 1
1 2
输出 #1
3
说明/提示
【数据范围】
- 对于 30 % 30\% 30% 的数据, M ≤ 10 M \le 10 M≤10;
- 对于全部的数据, M ≤ 100 M \le 100 M≤100。
【题目来源】
NOIP 2005 普及组第三题
代码(二维)
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
public class Main {
static int t,m;
static int []ti;
static int []vi;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
t=Integer.parseInt(stringTokenizer.nextToken());
m=Integer.parseInt(stringTokenizer.nextToken());
ti=new int[m+5];
vi=new int[m+5];
for(int i=1;i<=m;i++) {
stringTokenizer=new StringTokenizer(br.readLine());
ti[i]=Integer.parseInt(stringTokenizer.nextToken());
vi[i]=Integer.parseInt(stringTokenizer.nextToken());
}
int [][]dp=new int[m+5][t+5];
for(int i=1;i<=m;i++) {
for(int j=0;j<=t;j++) {
dp[i][j]=dp[i-1][j];
if(j>=ti[i]) {
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-ti[i]]+vi[i]);
}
}
}
System.out.println(dp[m][t]);
}
}
代码(一维)
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
public class Main {
static int t,m;
static int []ti;
static int []vi;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
t=Integer.parseInt(stringTokenizer.nextToken());
m=Integer.parseInt(stringTokenizer.nextToken());
ti=new int[m+5];
vi=new int[m+5];
for(int i=1;i<=m;i++) {
stringTokenizer=new StringTokenizer(br.readLine());
ti[i]=Integer.parseInt(stringTokenizer.nextToken());
vi[i]=Integer.parseInt(stringTokenizer.nextToken());
}
int []dp=new int[t+5];
for(int i=1;i<=m;i++) {
for(int j=t;j>=ti[i];j--) {
dp[j]=Math.max(dp[j],dp[j-ti[i]]+vi[i]);
}
}
System.out.println(dp[t]);
}
}
P1616 疯狂的采药
题目背景
此题为纪念 LiYuxiang 而生。
题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:"孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。"
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
1 1 1. 每种草药可以无限制地疯狂采摘。
2 2 2. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 t t t 和代表山洞里的草药的数目 m m m。
第 2 2 2 到第 ( m + 1 ) (m + 1) (m+1) 行,每行两个整数,第 ( i + 1 ) (i + 1) (i+1) 行的整数 a i , b i a_i, b_i ai,bi 分别表示采摘第 i i i 种草药的时间和该草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例 #1
输入 #1
70 3
71 100
69 1
1 2
输出 #1
140
说明/提示
数据规模与约定
- 对于 30 % 30\% 30% 的数据,保证 m ≤ 10 3 m \le 10^3 m≤103。
- 对于 100 % 100\% 100% 的数据,保证 1 ≤ m ≤ 10 4 1 \leq m \le 10^4 1≤m≤104, 1 ≤ t ≤ 10 7 1 \leq t \leq 10^7 1≤t≤107,且 1 ≤ m × t ≤ 10 7 1 \leq m \times t \leq 10^7 1≤m×t≤107, 1 ≤ a i , b i ≤ 10 4 1 \leq a_i, b_i \leq 10^4 1≤ai,bi≤104。
代码
java
import java.util.*;
import java.util.zip.CheckedInputStream;
import java.io.*;
public class Main {
static int t,m;
static int []ti;
static int []vi;
public static void main(String[] args) throws IOException{
// TODO 自动生成的方法存根
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer=new StringTokenizer(br.readLine());
t=Integer.parseInt(stringTokenizer.nextToken());
m=Integer.parseInt(stringTokenizer.nextToken());
ti=new int[m+5];
vi=new int[m+5];
for(int i=1;i<=m;i++) {
stringTokenizer=new StringTokenizer(br.readLine());
ti[i]=Integer.parseInt(stringTokenizer.nextToken());
vi[i]=Integer.parseInt(stringTokenizer.nextToken());
}
long []dp=new long[t+5];
for(int i=1;i<=m;i++) {
for(int j=ti[i];j<=t;j++) {
dp[j]=Math.max(dp[j],dp[j-ti[i]]+vi[i]);
}
}
System.out.println(dp[t]);
}
}