目录
A - Full Moon
题目描述
今天是第一天,高桥第一次看到满月是第M
天,之后每隔P
天可再次看到满月,问能看到满月的次数。
思路:模拟
public static void solve() throws IOException {
int n = readInt(), m = readInt(), p = readInt();
if (n < m) {//第一次都看不到
printWriter.println(0);
} else {
printWriter.println(1 + (n - m) / p);
}
}
B - Overlapping sheets
题目描述
一个平面有N
张矩形纸,求这些矩形纸能覆盖的面积。
思路:模拟
public static void solve() throws IOException {
int n = readInt();
int[][] grid = new int[105][105];
for (int i = 0; i < n; i++) {
int a = readInt(), b = readInt(), c = readInt(), d = readInt();
for (int p = a; p < b; p++) {
for (int q = c; q < d; q++) {
grid[p][q] = 1;
}
}
}
int s = 0;
for (int i = 0; i < 105; i++) {
for (int j = 0; j < 105; j++) {
if (grid[i][j] == 1) s++;
}
}
printWriter.println(s);
}
C - Blue Spring
题目描述
高桥准备进行一场持续N
天的旅行,每天的车票可以使用普通票,也可以使用一日通票。每天的普通票票价为 F i F_i Fi元,高桥也可以花P
元购买D
张一日通票,一日通票可以在任意一天使用。求最低消费。
思路:排序
public static void solve() throws IOException {
int n = readInt(), b = readInt(), p = readInt();
int[] arr = utils.nextIntArray(n);
Arrays.sort(arr, 1, n + 1);
long sum = 0;
for (int i = 1; i <= n; i++) sum += arr[i];
int cur = n;
for (; cur >= 1; cur--) {
long curS = 0;//当前D张普通票票价之和
int k = cur;
for (; k > cur - b && k >= 1; k--) {
curS += arr[k];
}
if (curS > p) {//如果>p,那么就用一日通票抵消
sum -= curS; sum += p;
cur = k + 1;
} else {//否则终止
break;
}
}
printWriter.println(sum);
}
D - General Weighted Max Matching
题目描述
给定一张带有N
个顶点的带权无向图,要求选任意条边,且边连接的点没有被重复选过,求最大边权之和。
思路:dfs
- 由于点的个数较少,所以我们对于每一个点,枚举这个点选和不选的情况。
static int n, m;
static int[][] g;
static long res = 0;
static boolean[] match;
public static void solve() throws IOException {
n = readInt();
g = new int[n + 1][n + 1];
match = new boolean[n + 1];
for (int i = 1; i <= n - 1; i++) {
for (int j = i + 1; j <= n; j++) {
int a = readInt();
g[i][j] = a; g[j][i] = a;
}
}
dfs(1, 0);
printWriter.println(res);
}
public static void dfs(int u, long sum) {
if (u > n) {// 当所有点都被选过
res = Math.max(res, sum);
return;
}
for (int i = u + 1; i <= n; i++) {
if (!match[u] && !match[i]) {// 两个点都没有被选过
match[u] = match[i] = true;
//注意是 u+1而不是 i+1,因为枚举的是 u的状态(选和不选)
dfs(u + 1, sum + g[u][i]);// 满足条件,选当前点 u,并添加权值 g[u][i]
match[u] = match[i] = false;
}
}
dfs(u + 1, sum);// 当前点 u不选
}
E - Sandwiches
题目描述
在一个长度为N
的序列A
中,找出满足以下条件的三元组的个数。
- 1 ≤ i < j < k ≤ N , A i = A k , A i ≠ A j 1 \le i \lt j \lt k \le N, A_i = A_k, A_i \ne A_j 1≤i<j<k≤N,Ai=Ak,Ai=Aj
样例输入
9 4 2 4 2 4 4 2 4 2
样例输出
28
思路:组合数学
- 首先存下每种数字出现的坐标集合,如果个数为
1
,则对答案没贡献,否则计算出两个相邻坐标i1
,i2
有多少个元素(设为p
),再计算出i1
右边有多少个和它相同的数字(假设为r
),并且计算出i2
左边有多少个和它相同的数字(假设为l
),那么总贡献为 p ∗ l ∗ r p * l * r p∗l∗r。
上面的i
指的是当前数字在坐标集合的下标(从0开始)
public static void solve() throws IOException {
int n = readInt();
int[] arr = utils.nextIntArray(n);
Map<Integer, List<Integer>> map = new HashMap<>();// 每一种数字的集合
for (int i = 1; i <= n; i++) {
// 如果 arr[i]的 value不存在则创建 ArrayList,如果存在则返回原来的 ArrayList
map.computeIfAbsent(arr[i], g -> new ArrayList<>()).add(i);
}
long res = 0;
for (List<Integer> indexes : map.values()) {
int size = indexes.size();
if (size == 1) continue;
for (int i = 0; i < size - 1; i++) {
long p = indexes.get(i + 1) - indexes.get(i) - 1;//两个相同的数字间有多少个不同的数字
res += p * (i + 1) * (size - i - 1);
}
}
printWriter.println(res);
}