Codeforces Round 894 (Div. 3) 题解 A-E

目录

  • A - Gift Carpet
  • B - Sequence Game
  • C - Flower City Fence
  • D - Ice Cream Balls
  • E - Kolya and Movie Theatre

A - Gift Carpet

原题链接

题目描述
给定nm列的字符数组,问是否能找出一种方案使得 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 2in,如果 a r r [ i − 1 ] ≤ a r r [ i ] arr[i - 1] \le arr[i] arr[i1]arr[i],那么就将 a r r [ i ] arr[i] arr[i]追加到arr2,现在,给出arr2,让你平凑出arr1并输出。

思路:观察

  • 对于arr2 1 ∼ n 1 \sim n 1n的数,将每个数追加到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,aiaj)的数组,数组的大小等于栅栏的高度,问是否可以将这些栅栏是否沿着斜对角线对称,如果对称输出YES,否则输出NO

思路:思维+差分

  • 观察:先将图形按题意翻转后是否和原图形相同,相同则对称。
  • 具体实现:从 1 ∼ n 1 \sim n 1n枚举大于等于 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(x1),设为cur,如果 cur == n那么 x为答案。
  • 否则我们需要找到一个 x,使得方案数 c u r < x ∗ ( x − 1 ) 2 cur \lt \frac {x * (x - 1)} {2} cur<2x(x1),然后往里面添加集合里已存在的数,每添加一个,方案数就会贡献 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的数组arrarr[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 arr1d1+arr3d2,等价于 a r r 1 + a r r 3 − d ∗ 3 arr_1 + arr_3 - d * 3 arr1+arr3d3

思路:优先队列

  • 观察得知:只需要知道最后一次看电影是第几天(假设为 i),那么满意度就会减少 i * d
  • 满意度小于0的电影不考虑看。
  • 用优先队列维护arr中偏大的数,sum为这些数的和,注意并不是 arr中的数越大越好,如果这个大的数在很后面,会导致 i ∗ d i * d id更大,满意度变得更少,所以需要枚举 1 ∼ n 1 \sim n 1n的所有数,取 m a x ( 0 , s u m − i ∗ d ) max(0, sum - i * d) max(0,sumid)
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);
}

你可能感兴趣的:(差分,二分,数学,算法,java)