很难避免,需要在错误中成长的困境。
毕竟人都是向下望就变得能坚强,
我亦尔耳。
本题总分: 5 5 5 分
【问题描述】
小蓝要把一个字符串中的字母按其在字母表中的顺序排列。
例如, L A N Q I A O \mathrm{LANQIAO} LANQIAO 排列后为 A A I L N O Q \mathrm{AAILNOQ} AAILNOQ。
又如, G O O D G O O D S T U D Y D A Y D A Y U P \mathrm{GOODGOODSTUDYDAYDAYUP} GOODGOODSTUDYDAYDAYUP 排列后为 A A D D D D D G G O O O O P S T U U Y Y Y \mathrm{AADDDDDGGOOOOPSTUUYYY} AADDDDDGGOOOOPSTUUYYY。
请问对于以下字符串,排列之后字符串是什么?
W H E R E T H E R E I S A W I L L T H E R E I S A W A Y \mathrm{WHERETHEREISAWILLTHEREISAWAY} WHERETHEREISAWILLTHEREISAWAY
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。
AAAEEEEEEHHHIIILLRRRSSTTWWWY
public class Test {
public static void main(String[] args) {
java.util.Arrays.stream("WHERETHEREISAWILLTHEREISAWAY".split("")).sorted().forEach(System.out::print);
}
}
整个活。
本题总分: 5 5 5 分
【问题描述】
2022 2022 2022 年 2 2 2 月 22 22 22 日 22 22 22: 20 20 20 是一个很有意义的时间,年份为 2022 2022 2022,由 3 3 3 个 2 2 2 和 1 1 1 个 0 0 0 组成,如果将月和日写成 4 4 4 位,为 0222 0222 0222,也是由 3 3 3 个 2 2 2 和 1 1 1 个 0 0 0 组成,如果将时间中的时和分写成 4 4 4 位,还是由 3 3 3 个 2 2 2 和 1 1 1 个 0 0 0 组成。
小蓝对这样的时间很感兴趣,他还找到了其它类似的例子,比如 111 111 111 年 10 10 10 月 11 11 11 日 01 01 01: 11 11 11, 2202 2202 2202 年 2 2 2 月 22 22 22 日 22 22 22: 02 02 02 等等。
请问,总共有多少个时间是这种年份写成 4 4 4 位、月日写成 4 4 4 位、时间写成 4 4 4 位后由 3 3 3 个一种数字和 1 1 1 个另一种数字组成。注意 1111 1111 1111 年 11 11 11 月 11 11 11 日 11 11 11: 11 11 11 不算,因为它里面没有两种数字。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
212
在 3 3 3 个相同的个位数中插入 1 1 1 个个位数,显然可以组成 4 4 4 个不同的数字(不一定是 4 4 4 位数),于是我们可以另一个合法的 月日时分 与 4 4 4 个不同的年份组成映射关系,只要统计出合法的 日月时分 个数,将其乘上一个 4 4 4,答案就被计算出来了。
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
public class Test {
public static void main(String[] args) { new Test().run(); }
void run() {
DateTimeFormatter date = DateTimeFormatter.ofPattern("MMdd");
DateTimeFormatter time = DateTimeFormatter.ofPattern("HHmm");
LocalDateTime start = LocalDateTime.of(0000, 01, 01, 00, 00);
LocalDateTime end = LocalDateTime.of(0000, 12, 31, 23, 59);
int[] buff = new int[128];
int ans = 0;
for (; start.compareTo(end) <= 0; start = start.plusMinutes(1)) {
for (char i = '0'; i <= '9'; ++i) buff[i] = 0;
for (byte b : start.format(date).getBytes()) ++buff[b];
boolean flag1 = true, flag3 = true;
for (char i = '0'; i <= '9'; ++i)
if (buff[i] == 1) flag1 = false;
else if (buff[i] == 3) flag3 = false;
if (flag1 || flag3) continue;
for (byte b : start.format(time).getBytes()) --buff[b];
for (char i = '0'; i <= '9'; ++i)
if (buff[i] != 0) flag1 = true;
if (!flag1) ++ans;
}
System.out.println(4 * ans);
}
}
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 10 10 10 分
【问题描述】
在 I S O \mathrm{ISO} ISO 国际标准中定义了 A 0 \mathrm A0 A0 纸张的大小为 1189 m m × 841 m m 1189\mathrm{mm} × 841\mathrm{mm} 1189mm×841mm,将 A 0 \mathrm A0 A0 纸沿长边对折后为 A 1 \mathrm A1 A1 纸,大小为 841 m m × 594 m m 841\mathrm{mm} × 594\mathrm{mm} 841mm×594mm,在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。将 A 1 \mathrm A1 A1 纸沿长边对折后为 A 2 \mathrm A2 A2 纸,依此类推。
输入纸张的名称,请输出纸张的大小。
【输入格式】
输入一行包含一个字符串表示纸张的名称,该名称一定是 A 0 \mathrm A0 A0、 A 1 \mathrm A1 A1、 A 2 \mathrm A2 A2、 A 3 \mathrm A3 A3、 A 4 \mathrm A4 A4、 A 5 \mathrm A5 A5、 A 6 \mathrm A6 A6、 A 7 \mathrm A7 A7、 A 8 \mathrm A8 A8、 A 9 \mathrm A9 A9 之一。
【输出格式】
输出两行,每行包含一个整数,依次表示长边和短边的长度。
【样例输入 1】
A0
【样例输出 1】
1189
841
【样例输入 2】
A1
【样例输出 2】
841
594
签到题, J a v a 8 \mathrm{Java}\ 8 Java 8 支持 switch
String
对象,
直接用 switch
的特性写了。
import java.util.Scanner;
public class Main {
public static void main(String[] args) { new Main().run(); }
int length = 1189, wide = 841;
void cut() {
int temp = wide;
wide = length / 2;
length = temp;
}
void run() {
switch (new Scanner(System.in).next()) {
case "A9": cut();
case "A8": cut();
case "A7": cut();
case "A6": cut();
case "A5": cut();
case "A4": cut();
case "A3": cut();
case "A2": cut();
case "A1": cut();
default: System.out.printf("%d\n%d", length, wide);
}
}
}
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 10 10 10 分
【问题描述】
给定 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots , a_n a1,a2,⋯,an,求它们两两相乘再相加的和,即 S = a 1 ⋅ a 2 + a 1 ⋅ a 3 + ⋯ + a 1 ⋅ a n + a 2 ⋅ a 3 + ⋯ + a n − 2 ⋅ a n − 1 + a n − 2 ⋅ a n + a n − 1 ⋅ a n 。 S = a_1\cdot a_2 + a_1\cdot a_3 + \cdots + a_1\cdot a_n + a_2\cdot a_3 +\cdots + a_{n−2}\cdot a_{n−1} + a_{n−2}\cdot a_n + a_{n−1}\cdot a_n。 S=a1⋅a2+a1⋅a3+⋯+a1⋅an+a2⋅a3+⋯+an−2⋅an−1+an−2⋅an+an−1⋅an。
【输入格式】
输入的第一行包含一个整数 n n n 。
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2,\cdots,a_n a1,a2,⋯,an。
【输出格式】
输出一个整数 S S S,表示所求的和。请使用合适的数据类型进行运算。
【样例输入】
4
1 3 6 9
【样例输出】
117
【评测用例规模与约定】
对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 1000 , 1 ≤ a i ≤ 100 1 ≤ n ≤ 1000,1 ≤ a_i ≤ 100 1≤n≤1000,1≤ai≤100。
对于所有评测用例, 1 ≤ n ≤ 200000 , 1 ≤ a i ≤ 1000 1 ≤ n ≤ 200000,1 ≤ a_i ≤ 1000 1≤n≤200000,1≤ai≤1000。
将 S S S 中包含 a 1 a_1 a1 的项整理出来,有:
S = a 1 ⋅ ( a 2 + a 3 + ⋯ + a n ) + a 2 ⋅ a 3 + ⋯ + a n − 2 ⋅ a n − 1 + a n − 2 ⋅ a n + a n − 1 ⋅ a n S=a_1\cdot(a_2+a_3+\cdots+a_n)+ a_2\cdot a_3 +\cdots + a_{n−2}\cdot a_{n−1} + a_{n−2}\cdot a_n + a_{n−1}\cdot a_n S=a1⋅(a2+a3+⋯+an)+a2⋅a3+⋯+an−2⋅an−1+an−2⋅an+an−1⋅an
同样的将余项中包含 a 2 a_2 a2、 a 3 a_3 a3、 ⋯ \cdots ⋯、 a n a_n an 的项整理出来:
S = a 1 ⋅ ( a 2 + a 3 + ⋯ + a n ) + a 2 ⋅ ( a 3 + a 4 + ⋯ + a n ) + ⋯ + a n − 1 ⋅ a n = a 1 ⋅ ∑ i = 2 n a i + a 2 ⋅ ∑ i = 3 n a i + ⋯ + a n − 1 ⋅ ∑ i = n n a i \begin{aligned}S&=a_1\cdot(a_2+a_3+\cdots+a_n)+ a_2\cdot(a_3+a_4+\cdots+a_n)+\cdots+a_{n-1}\cdot a_n\\&=a_1\cdot\sum_{i=2}^na_i+a_2\cdot \sum_{i=3}^na_i+\cdots+a_{n-1}\cdot\sum_{i=n}^{n}a_i\end{aligned} S=a1⋅(a2+a3+⋯+an)+a2⋅(a3+a4+⋯+an)+⋯+an−1⋅an=a1⋅i=2∑nai+a2⋅i=3∑nai+⋯+an−1⋅i=n∑nai
也就 S S S 等于每个元素乘以右边所有元素的和的和,考虑到实现计算的代码量,我们将 S S S 的项重排,重新整理出:
S = a 1 ⋅ ∑ i = 1 0 a i + a 2 ⋅ ∑ i = 1 1 a i + ⋯ + a n ⋅ ∑ i = 1 n − 1 a i S=a_1\cdot\displaystyle\sum_{i=1}^{0}a_i+a_2\cdot \sum_{i=1}^{1}a_i+\cdots+a_{n}\cdot\sum_{i=1}^{n-1}a_i S=a1⋅i=1∑0ai+a2⋅i=1∑1ai+⋯+an⋅i=1∑n−1ai
import java.io.StreamTokenizer;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) { new Main().run(); }
void run() {
int n = nextInt(), sum = 0;
long a, ans = 0;
while(n-- > 0) {
a = nextInt();
ans += a * sum;
sum += a;
}
System.out.println(ans);
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int)in.nval;
}
}
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 15 15 15 分
【问题描述】
已知 3 3 3 个矩形的大小依次是 a 1 × b 1 a_1 × b_1 a1×b1、 a 2 × b 2 a_2 × b_2 a2×b2 和 a 3 × b 3 a_3 × b_3 a3×b3。用这 3 3 3 个矩形能拼出的所有多边形中,边数最少可以是多少?
例如用 3 × 2 3 × 2 3×2 的矩形(用 A \mathrm A A 表示)、 4 × 1 4 × 1 4×1 的矩形(用 B \mathrm B B 表示)和 2 × 4 2 × 4 2×4 的矩形(用 C \mathrm C C 表示)可以拼出如下 4 4 4 边形。
例如用 3 × 2 3 × 2 3×2 的矩形(用 A \mathrm A A 表示)、 3 × 1 3 × 1 3×1 的矩形(用 B \mathrm B B 表示)和 1 × 1 1 × 1 1×1 的矩形(用 C \mathrm C C 表示)可以拼出如下 6 6 6 边形。
【输入格式】
输入包含多组数据。
第一行包含一个整数 T T T,代表数据组数。
以下 T T T 行,每行包含 6 6 6 个整数 a 1 , b 1 , a 2 , b 2 , a 3 , b 3 a_1, b_1, a_2, b_2, a_3, b_3 a1,b1,a2,b2,a3,b3,其中 a 1 , b 1 a_1, b_1 a1,b1 是第一个矩形的边长, a 2 , b 2 a_2, b_2 a2,b2 是第二个矩形的边长, a 3 , b 3 a_3, b_3 a3,b3 是第三个矩形的边长。
【输出格式】
对于每组数据,输出一个整数代表答案。
【样例输入】
2
2 3 4 1 2 4
1 2 3 4 5 6
【样例输出】
4
8
【评测用例规模与约定】
对于 10 % 10\% 10% 的评测用例, 1 ≤ T ≤ 5 , 1 ≤ a 1 , b 1 , a 2 , b 2 , a 3 , b 3 ≤ 10 , a 1 = a 2 = a 3 1 ≤ T ≤ 5,1 ≤ a_1, b_1, a_2, b_2, a_3, b_3 ≤ 10,a_1 = a_2 =a_3 1≤T≤5,1≤a1,b1,a2,b2,a3,b3≤10,a1=a2=a3。
对于 30 % 30\% 30% 的评测用例, 1 ≤ T ≤ 5 , 1 ≤ a 1 , b 1 , a 2 , b 2 , a 3 , b 3 ≤ 10 1 ≤ T ≤ 5,1 ≤ a_1, b_1, a_2, b_2, a_3, b_3 ≤ 10 1≤T≤5,1≤a1,b1,a2,b2,a3,b3≤10。
对于 60 % 60\% 60% 的评测用例, 1 ≤ T ≤ 10 , 1 ≤ a 1 , b 1 , a 2 , b 2 , a 3 , b 3 ≤ 20 1 ≤ T ≤ 10,1 ≤ a_1, b_1, a_2, b_2, a_3, b_3 ≤ 20 1≤T≤10,1≤a1,b1,a2,b2,a3,b3≤20。
对于所有评测用例, 1 ≤ T ≤ 1000 , 1 ≤ a 1 , b 1 , a 2 , b 2 , a 3 , b 3 ≤ 100 1 ≤ T ≤ 1000,1 ≤ a_1, b_1, a_2, b_2, a_3, b_3 ≤ 100 1≤T≤1000,1≤a1,b1,a2,b2,a3,b3≤100。
// 因为是分类讨论,所以不想写了。
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 15 15 15 分
【问题描述】
给定一个长度为 n n n 的数列 A 1 , A 2 , ⋯ , A n A_1, A_2, \cdots , A_n A1,A2,⋯,An 和一个非负整数 x x x,给定 m m m 次查询, 每次询问能否从某个区间 [ l , r ] [l,r] [l,r] 中选择两个数使得他们的异或等于 x x x。
【输入格式】
输入的第一行包含三个整数 n , m , x n, m, x n,m,x。
第二行包含 n n n 个整数 A 1 , A 2 , ⋯ , A n A_1, A_2,\cdots, A_n A1,A2,⋯,An。
接下来 m m m 行,每行包含两个整数 l i , r i l_i,r_i li,ri 表示询问区间 [ l i , r i ] [l_i,r_i] [li,ri]。
【输出格式】
对于每个询问, 如果该区间内存在两个数的异或为 x x x 则输出 y e s \mathrm{yes} yes, 否则输出 n o \mathrm{no} no。
【样例输入】
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
【样例输出】
yes
no
yes
no
【样例说明】
显然整个数列中只有 2 , 3 2, 3 2,3 的异或为 1 1 1。
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例, 1 ≤ n , m ≤ 100 1 ≤ n, m ≤ 100 1≤n,m≤100;
对于 40 % 40\% 40% 的评测用例, 1 ≤ n , m ≤ 1000 1 ≤ n, m ≤ 1000 1≤n,m≤1000;
对于所有评测用例, 1 ≤ n , m ≤ 100000 , 0 ≤ x < 2 20 , 1 ≤ l i ≤ r i ≤ n , 0 ≤ A i < 2 20 1 ≤ n, m ≤ 100000 ,0 ≤ x < 2^{20} ,1 ≤ l_i ≤ r_i ≤ n ,0 ≤ A_i < 2^{20} 1≤n,m≤100000,0≤x<220,1≤li≤ri≤n,0≤Ai<220。
对于 [ l i , r i ] [l_i,r_i] [li,ri] 中的某个数 A k A_k Ak,若其中还存在一个数 A g A_g Ag 使得 A k ⊕ A g = x A_k \oplus A_g = x Ak⊕Ag=x,根据异或自反性质有: A k ⊕ A g ⊕ A k = x ⊕ A k A g = x ⊕ A k \begin{aligned}A_k \oplus A_g \oplus A_k&=x \oplus A_k\\A_g&=x \oplus A_k\end{aligned} Ak⊕Ag⊕AkAg=x⊕Ak=x⊕Ak 容易想到离线莫队来处理这个问题,具体地说:
我们声明一个整形 c n t \mathrm{cnt} cnt 并建立一个 m a p \mathrm{map} map,一开始它存储了 [ 0 , 0 ] [0,0] [0,0] 间每个数出现的次数,对于每次往区间里面加入一个数 A k A_k Ak,将 c n t \mathrm{cnt} cnt 加上一个 A g A_g Ag 出现次数,每次减去一个数 A k A_k Ak,将 c n t \mathrm{cnt} cnt 减去一个 A g A_g Ag 出现次数,直至区间变为 [ l i , r i ] [l_i,r_i] [li,ri],
此时,根据 c n t \mathrm{cnt} cnt 是否大于 1 1 1 来回答是否存在题目所述的两个数。
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.io.*;
public class Main {
public static void main(String[] args) { new Main().run(); }
int block, x, cnt = 0;
Map<Integer, Integer> map = new HashMap();
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = nextInt(), m = nextInt();
boolean[] ans = new boolean[m];
Query[] querys = new Query[m];
block = (int)Math.sqrt(n);
int[] A = new int[n + 1];
x = nextInt();
for (int i = 1; i <= n; ++i) A[i] = nextInt();
for (int i = 0; i < n; ++i)
querys[i] = new Query(i, nextInt(), nextInt());
Arrays.sort(querys);
int l = 1, r = 0;
for (int i = 0; i < m; ++i) {
while (querys[i].r > r) add(A[++r]);
while (querys[i].l < l) add(A[--l]);
while (querys[i].r < r) move(A[r--]);
while (querys[i].l > l) move(A[l++]);
ans[querys[i].idx] = cnt > 0;
}
for (int i = 0; i < m; ++i)
out.println(ans[i] ? "yes" : "no");
out.flush();
}
void add(int a) {
if (map.containsKey(a ^ x))
cnt += map.get(a ^ x);
map.put(a, map.getOrDefault(a, 0) + 1);
}
void move(int a) {
if (map.containsKey(a ^ x))
cnt -= map.get(a ^ x);
int tmp = map.get(a);
if (tmp == 1) map.remove(a);
else map.put(a, tmp - 1);
}
class Query implements Comparable<Query> {
int l, r, idx;
Query(int idx, int l, int r) {
this.idx = idx;
this.l = l;
this.r = r;
}
@Override
public int compareTo(Query q) {
return this.l / block == q.l / block ? ((this.l / block) % 2 == 0 ? this.r - q.r : q.r - this.r) : this.l - q.l;
}
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int)in.nval;
}
}
但其实可以预处理出 f r f_r fr,其意义为 [ f r , r ] [f_r,r] [fr,r] 中存在一对 k k k、 g g g , f r ≤ k ≤ g ≤ r f_r \leq k \leq g \leq r fr≤k≤g≤r 使得 A k ⊕ A g = x A_k \oplus A_g =x Ak⊕Ag=x 且 f r f_r fr 最大,若不存在则另 f r = 0 f_r = 0 fr=0。
对于每一次询问 [ l i , r i ] [l_i,r_i] [li,ri],我们只需判断 l i li li 和 f r i f_{r_i} fri 的大小关系就能确定 [ l i , r i ] [l_i,r_i] [li,ri] 之间是否存在两个数,它们的异或等于 x x x。
现在考虑转移,对于每一个 r r r,我们判断下标大于 r r r 的元素中是否存在 A r ⊕ x A_r \oplus x Ar⊕x,其中最靠 r r r 的是 f r f_r fr 的一个候选值,同时我们还要考虑 [ f r − 1 , r − 1 ] [f_{r-1},r-1] [fr−1,r−1] 中是否有更优的方案,最终有状态转移方程: f r = max { f r − 1 , max { i ∣ A i = A r ⊕ x } } f_r=\max\{f_{r-1},\max\{i|A_i=A_r\oplus x\}\} fr=max{fr−1,max{i∣Ai=Ar⊕x}}
import java.io.*;
public class Main {
public static void main(String[] args) { new Main().run(); }
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = nextInt(), m = nextInt(), x = nextInt();
int[] map = new int[1 << 20];
int[] f = new int[n + 1];
for (int r = 1; r <= n; ++r) {
int a = nextInt();
f[r] = max(f[r - 1], map[a ^ x]);
map[a] = r;
}
for (int i = 0; i < m; ++i) {
int l = nextInt();
int r = nextInt();
out.println(f[r] >= l ? "yes" : "no");
}
out.flush();
}
int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int)in.nval;
}
}
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 20 20 20 分
【问题描述】
给定两个不同的正整数 a , b a, b a,b,求一个正整数 k k k 使得 gcd ( a + k , b + k ) \gcd(a + k, b + k) gcd(a+k,b+k) 尽可能大,其中 gcd ( a , b ) \gcd(a, b) gcd(a,b) 表示 a a a 和 b b b 的最大公约数,如果存在多个 k k k,请输出所有满足条件的 k k k 中最小的那个。
【输入格式】
输入一行包含两个正整数 a , b a, b a,b,用一个空格分隔。
【输出格式】
输出一行包含一个正整数 k k k。
【样例输入】
5 7
【样例输出】
1
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例, a < b ≤ 1 0 5 a < b ≤ 10^5 a<b≤105;
对于 40 % 40\% 40% 的评测用例, a < b ≤ 1 0 9 a < b ≤ 10^9 a<b≤109;
对于所有评测用例, 1 ≤ a < b ≤ 1 0 18 1 ≤ a < b ≤ 10^{18} 1≤a<b≤1018。
更相减损术告诉我们,对于整数 a , b a,b a,b,若 a ≥ b a\geq b a≥b,都有 gcd ( a , b ) = gcd ( a − b , b ) = gcd ( a , a − b ) \gcd(a,b) = \gcd(a-b,b) = \gcd(a,a-b) gcd(a,b)=gcd(a−b,b)=gcd(a,a−b)。
将 k k k 代入到式中,我们的目标就是使 gcd ( a + k , a − b ) \gcd(a+k,a-b) gcd(a+k,a−b)、 gcd ( b + k , a − b ) \gcd(b+k,a-b) gcd(b+k,a−b) 最大。
显然最大为 ∣ a − b ∣ |a-b| ∣a−b∣,此时 k k k 取 min { − a , − b } ( m o d ∣ a − b ∣ ) \min\{-a,-b\} \pmod{|a-b|} min{−a,−b}(mod∣a−b∣) 最小。
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) { new Main().run(); }
void run() {
InputReader in = new InputReader(System.in);
long a = in.nextLong(), b = in.nextLong();
long c = abs(a - b);
if (c == 0 || c == 1) System.out.print("1");
else System.out.print(min((-a % c + c) % c, (-b % c + c) % c));
}
long min(long arg1, long arg2) { return arg1 < arg2 ? arg1 : arg2; }
long abs(long arg) { return arg > 0 ? arg : -arg; }
class InputReader {
BufferedReader reader;
StringTokenizer token;
InputReader(InputStream in) { this.reader = new BufferedReader(new InputStreamReader(in)); }
String next() {
if (token == null || !token.hasMoreTokens()) {
try {
token = new StringTokenizer(reader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return token.nextToken();
}
long nextLong() { return Long.parseLong(next()); }
}
}
表达式写出来后,
感觉怪怪的。。。
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 20 20 20 分
【问题描述】
小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。
河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降 1 1 1,当石头的高度下降到 0 0 0 时小青蛙不能再跳到这块石头上 ( ( (某次跳跃后使石头高度下降到 0 0 0 是允许的 ) ) )。
小青蛙一共需要去学校上 x x x 天课,所以它需要往返 2 x 2x 2x 次。当小青蛙具有一个跳跃能力 y y y 时,它能跳不超过 y y y 的距离。
请问小青蛙的跳跃能力至少是多少才能用这些石头上完 x x x 次课。
【输入格式】
输入的第一行包含两个整数 n , x n, x n,x,分别表示河的宽度和小青蛙需要去学校的天数。请注意 2 x 2x 2x 才是实际过河的次数。
第二行包含 n − 1 n − 1 n−1 个非负整数 H 1 , H 2 , ⋯ , H n − 1 H_1, H_2,\cdots, H_{n−1} H1,H2,⋯,Hn−1,其中 H i > 0 H_i > 0 Hi>0 表示在河中与小青蛙的家相距 i i i 的地方有一块高度为 H i H_i Hi 的石头, H i = 0 H_i = 0 Hi=0 表示这个位置没有石头。
【输出格式】
输出一行,包含一个整数,表示小青蛙需要的最低跳跃能力。
【样例输入】
5 1
1 0 1 0
【样例输出】
4
【样例解释】
由于只有两块高度为 1 1 1 的石头,所以往返只能各用一块。第 1 1 1 块石头和对岸的距离为 4 4 4,如果小青蛙的跳跃能力为 3 3 3 则无法满足要求。所以小青蛙最少需要 4 4 4 的跳跃能力。
【评测用例规模与约定】
对于 30 % 30\% 30% 的评测用例, n ≤ 100 n ≤ 100 n≤100;
对于 60 % 60\% 60% 的评测用例, n ≤ 1000 n ≤ 1000 n≤1000;
对于所有评测用例, 1 ≤ n ≤ 1 0 5 , 1 ≤ x ≤ 1 0 9 , 1 ≤ H i ≤ 1 0 4 1 ≤ n ≤ 10^5, 1 ≤ x ≤ 10^9, 1 ≤ H^i ≤ 10^4 1≤n≤105,1≤x≤109,1≤Hi≤104。
可以将转成最大流模型,然后二分答案。
但应付 1 0 5 10^5 105 的数据还是显得捉襟见肘,
摆了,不写了。
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 25 25 25 分
【问题描述】
记 f ( x ) f(x) f(x) 为 x x x 的所有因数的平方的和。例如 : f ( 12 ) = 1 2 + 2 2 + 3 2 + 4 2 + 6 2 + 1 2 2 :f(12) = 1^2 + 2^2 + 3^2 + 4^2 + 6^2 +12^2 :f(12)=12+22+32+42+62+122。
定义 g ( n ) = ∑ i = 1 n f ( i ) g(n) = \sum^n_{i=1}f(i) g(n)=∑i=1nf(i)。给定 n n n, 求 g ( n ) g(n) g(n) 除以 1 0 9 + 7 10^9 + 7 109+7 的余数。
【输入格式】
输入一行包含一个正整数 n n n。
【输出格式】
输出一个整数表示答案 g ( n ) g(n) g(n) 除以 1 0 9 + 7 10^9 + 7 109+7 的余数。
【样例输入】
100000
【样例输出】
680584257
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例, n ≤ 1 0 5 n ≤ 10^5 n≤105。
对于 30 % 30\% 30% 的评测用例, n ≤ 1 0 7 n ≤ 10^7 n≤107。
对于所有评测用例, 1 ≤ n ≤ 1 0 9 1 ≤ n ≤ 10^9 1≤n≤109。
根据倍数法求 [ 1 , n ] [1,n] [1,n] 中每个数的因数的完备性可得知:
[ 1 , n ] [1,n] [1,n] 中因数有 1 1 1 的数有 ⌊ n 1 ⌋ \lfloor\frac n1\rfloor ⌊1n⌋ 个;
[ 1 , n ] [1,n] [1,n] 中因数有 2 2 2 的数有 ⌊ n 2 ⌋ \lfloor\frac n2\rfloor ⌊2n⌋ 个;
⋯ ⋯ \cdots\cdots ⋯⋯
[ 1 , n ] [1,n] [1,n] 中因数有 n n n 的数有 ⌊ n n ⌋ \lfloor\frac nn\rfloor ⌊nn⌋ 个。
于是我们可以将和式 g ( n ) = ∑ i = 1 n f ( i ) g(n) = \sum^n_{i=1}f(i) g(n)=∑i=1nf(i) 演绎为
g ( n ) = ∑ i = 1 n ( ⌊ n i ⌋ i 2 ) = ∑ l ∣ l ∈ u n i q u e { ⌊ n i ⌋ ∣ i ∈ [ 1 , n ] } ( ⌊ n ⌊ n l ⌋ ⌋ − l + 1 ) ( l 2 + ( l + 1 ) 2 + ⋯ + ⌊ n ⌊ n l ⌋ ⌋ 2 ) \begin{aligned}g(n) &= \sum_{i=1}^n(\lfloor\frac ni\rfloor i^2)\\&=\sum_{l|l\in\mathrm{unique\{\lfloor\frac ni\rfloor|i\in[1,n]\}}}\left(\left\lfloor\dfrac{\ n\ }{\lfloor\frac nl\rfloor}\right\rfloor-l+1\right)(l^2+(l+1)^2+\cdots+\left\lfloor\frac{\ n\ }{\lfloor\frac nl\rfloor}\right\rfloor^2)\end{aligned} g(n)=i=1∑n(⌊in⌋i2)=l∣l∈unique{⌊in⌋∣i∈[1,n]}∑(⌊⌊ln⌋ n ⌋−l+1)(l2+(l+1)2+⋯+⌊⌊ln⌋ n ⌋2)
求解。
容易想到使用数论分块将和式计算的复杂度优化至 O ( n ) O(\sqrt n) O(n)。
import java.io.StreamTokenizer;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) { new Main().run(); }
int p = 1000000007, inv6 = 166666668;
void run() {
int n = nextInt();
long tmp, sum = 0, ans = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
tmp = sum;
sum = r * (r + 1L) % p * (2 * r + 1) % p * inv6 % p;
ans = (ans + (n / l) * (sum - tmp) + p) % p;
}
System.out.println(ans);
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int)in.nval;
}
}
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 25 25 25 分
【问题描述】
给定一个长度为 N N N 的整数序列 : A 1 , A 2 , ⋯ , A N :A_1, A_2,\cdots, A_N :A1,A2,⋯,AN。现在你有一次机会,将其中连续的 K K K 个数修改成任意一个相同值。请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。
最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。
【输入格式】
输入第一行包含两个整数 N N N 和 K K K。
第二行包含 N N N 个整数 A 1 , A 2 , ⋯ , A N A_1, A_2,\cdots, A_N A1,A2,⋯,AN。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
5 1
1 4 2 8 5
【样例输出】
4
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例, 1 ≤ K ≤ N ≤ 100 1 ≤ K ≤ N ≤ 100 1≤K≤N≤100;
对于 30 % 30\% 30% 的评测用例, 1 ≤ K ≤ N ≤ 1000 1 ≤ K ≤ N ≤ 1000 1≤K≤N≤1000;
对于 50 % 50\% 50% 的评测用例, 1 ≤ K ≤ N ≤ 10000 1 ≤ K ≤ N ≤ 10000 1≤K≤N≤10000;
对于所有评测用例, 1 ≤ K ≤ N ≤ 1 0 5 , 1 ≤ A i ≤ 1 0 6 1 ≤ K ≤ N ≤ 10^5,1 ≤ A_i ≤ 10^6 1≤K≤N≤105,1≤Ai≤106。
动态规划然后线性扫描一遍,吃个饭回来写。