目录
A - Gift Carpet
题目描述
给定n
行m
列的字符数组,问是否能找出一种方案使得v
所在列小于i
所在列,且i
所在列小于k
所在列,且k
所在列小于a
所在列,如果可以输出YES
,否则输出NO
。
思路:模拟
- 先枚举列,再枚举行,用变量
cnt
维护vika
每个字母前面需要有的字母个数。
public static void solve() throws IOException {
int n = readInt(), m = readInt();
char[][] chars = utils.nextCharArray(n, m);
int cnt = 0;
for (int i = 1; i <= m; i++) {// 先枚举列
for (int j = 1; j <= n; j++) {// 再枚举行
char ch = chars[j][i];
if (cnt == 0 && ch == 'v') {
cnt++; break;
} else if (cnt == 1 && ch == 'i') {
cnt++; break;
} else if (cnt == 2 && ch == 'k') {
cnt++; break;
} else if (cnt == 3 && ch == 'a') {
cnt++; break;
}
}
}
printWriter.println(cnt == 4 ? "YES" : "NO");
}
B - Sequence Game
题目描述
给定一个长度为n
的数组arr1
,和一个新数组arr2
,首先赋值 a r r 2 [ 1 ] = a r r 1 [ 1 ] arr2[1]=arr1[1] arr2[1]=arr1[1],对于 2 ≤ i ≤ n 2 \le i \le n 2≤i≤n,如果 a r r [ i − 1 ] ≤ a r r [ i ] arr[i - 1] \le arr[i] arr[i−1]≤arr[i],那么就将 a r r [ i ] arr[i] arr[i]追加到arr2
,现在,给出arr2
,让你平凑出arr1
并输出。
思路:观察
- 对于
arr2
中 1 ∼ n 1 \sim n 1∼n的数,将每个数追加到arr1
当中,如果 a r r [ i ] > a r r [ i + 1 ] arr[i] \gt arr[i + 1] arr[i]>arr[i+1],那么还要追加 a r r [ i + 1 ] arr[i + 1] arr[i+1]
public static void solve() throws IOException {
int n = readInt();
int[] arr = utils.nextIntArray(n);
List<Integer> list = new ArrayList<>();
if (n == 1) {
printWriter.println(1);
printWriter.println(arr[1]);
return;
}
for (int i = 1; i <= n; i++) {
list.add(arr[i]);
if (i + 1 <= n && arr[i] > arr[i + 1]) {
list.add(arr[i + 1]);
}
}
printWriter.println(list.size());
for (int p : list) printWriter.print(p + " ");
printWriter.println();
}
C - Flower City Fence
题目描述
给定一个长度为n
且非递增( i < j , a i ≥ a j i \lt j,a_i \ge a_j i<j,ai≥aj)的数组,数组的大小等于栅栏的高度,问是否可以将这些栅栏是否沿着斜对角线对称,如果对称输出YES
,否则输出NO
。
思路:思维+差分
- 观察:先将图形按题意翻转后是否和原图形相同,相同则对称。
- 具体实现:从 1 ∼ n 1 \sim n 1∼n枚举大于等于
i
的数的个数作为新数组的第i
个位置的值,个数用差分数组来维护。(不懂画个图就好了,用第二个和第五个测试数据模拟)
public static void solve() throws IOException {
int[] arr = utils.nextIntArray(n);
List<Long> list = new ArrayList<>();
long[] diff = new long[n + 10];
for (int i = 1; i <= n; i++) {
if (arr[i] >= n) {
diff[1]++; diff[n + 1]--;
} else {
diff[1]++; diff[arr[i] + 1]--;
}
}
for (int i = 1; i <= n; i++) diff[i] += diff[i - 1];
list.add(0l);
for (int i = 1; i <= n; i++) {
list.add(diff[i]);
}
for (int i = 1; i <= n; i++) {
if (list.get(i) != arr[i]) {
printWriter.println("NO");
return;
}
}
printWriter.println("YES");
}
D - Ice Cream Balls
题目描述
给定一个整数n
作为方案数,你需要求出一个集合,集合中的任意两个元素可以组成一种方案,对于方案 { 1 , 1 } ≠ { 1 , 2 } \{1,1\} \neq \{1,2\} {1,1}={1,2}但是 { 1 , 2 } = { 2 , 1 } \{1,2\}=\{2,1\} {1,2}={2,1},比如集合中的元素有 { 1 , 1 , 2 } \{1,1,2\} {1,1,2},那么你可以凑出 { 1 , 1 } \{1,1\} {1,1}和 { 1 , 2 } \{1,2\} {1,2}两种方案。你需要求出这个集合中元素的个数。
思路:组合数学+二分
- 设集合元素为
x
个,如果这个集合中每个元素都不同,那么方案数为 x ∗ ( x − 1 ) 2 \frac {x * (x - 1)} {2} 2x∗(x−1),设为cur
,如果cur == n
那么x
为答案。- 否则我们需要找到一个
x
,使得方案数 c u r < x ∗ ( x − 1 ) 2 cur \lt \frac {x * (x - 1)} {2} cur<2x∗(x−1),然后往里面添加集合里已存在的数,每添加一个,方案数就会贡献 1。
public static void solve() throws IOException {
long n = readLong();
// 集合至少有两个元素
long l = 2, r = utils.forceInt(4e9);
while (l + 1 < r) {
long mid = (l + r) / 2;
if (mid * (mid - 1) / 2 <= n) {
l = mid;
} else {
r = mid;
}
}
if (l * (l - 1) / 2 == n) {
printWriter.println(l);
} else {
// l是集合中互不相同的元素的个数
// n - l * (l - 1) / 2就是再往里面添加集合里已存在的数的个数
printWriter.println(l + n - l * (l - 1) / 2);
}
}
E - Kolya and Movie Theatre
题目描述
你想要去看电影,给定一个长度为n
的数组arr
,arr[i]
表示第i
天的电影所能提供的满意度。但是越长时间不去电影院(你第0天看过电影),那么电影所能提供的满意度越低,降低的值为上一次到这一次看电影的时间间隔 *d
,你最多只能花m
天去看电影,求能获得的最大满意度。
样例输入
1 // 测试数据的个数 5 2 2 // n m d 3 2 5 4 6
样例输出
2
样例解释
只看第一天和第三天的电影,满意度为 a r r 1 − d ∗ 1 + a r r 3 − d ∗ 2 arr_1 - d * 1 + arr_3 - d * 2 arr1−d∗1+arr3−d∗2,等价于 a r r 1 + a r r 3 − d ∗ 3 arr_1 + arr_3 - d * 3 arr1+arr3−d∗3。
思路:优先队列
- 观察得知:只需要知道最后一次看电影是第几天(假设为
i
),那么满意度就会减少i
*d
。- 满意度小于
0
的电影不考虑看。- 用优先队列维护
arr
中偏大的数,sum
为这些数的和,注意并不是arr
中的数越大越好,如果这个大的数在很后面,会导致 i ∗ d i * d i∗d更大,满意度变得更少,所以需要枚举 1 ∼ n 1 \sim n 1∼n的所有数,取 m a x ( 0 , s u m − i ∗ d ) max(0, sum - i * d) max(0,sum−i∗d)。
public static void solve() throws IOException {
int n = readInt(), m = readInt(), d = readInt();
int[] arr = utils.nextIntArray(n);
long sum = 0, max = 0;
PriorityQueue<Integer> deque = new PriorityQueue<>();
for (int i = 1; i <= n; i++) {
if (arr[i] < 0) continue;//这场电影的满意度为负数
if (deque.size() < m) {
deque.offer(arr[i]);
sum += arr[i];
} else {// 已经去过了m天,那么维护较大的数
int t = deque.peek();
if (arr[i] > t) {
deque.poll();
deque.offer(arr[i]);
sum -= t;
sum += arr[i];
}
}
max = Math.max(max, sum - 1l * i * d);
}
printWriter.println(max);
}