1. 程式人生 > >Codeforces - 977F. Consecutive Subsequence( Map + DP) & 1097B. Petr and a Combination Lock(列舉)

Codeforces - 977F. Consecutive Subsequence( Map + DP) & 1097B. Petr and a Combination Lock(列舉)

Codeforces - 977F. Consecutive Subsequence( Map + DP) & 1097B. Petr and a Combination Lock(列舉)


Codeforces - 977F. Consecutive Subsequence( Map + DP)

題目連結

題目

求最長的連續遞增子序列(注意是連續遞增

(也就是值前後相差為1)), 輸出長度以及子序列的下標。

在這裡插入圖片描述
在這裡插入圖片描述

解析

這題一開始以為是最長遞增子序列的變形,但是程式碼O(N^2)內會超時。

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class Main {

    static int[] getDp(int[] arr){
        int[] dp = new int[arr.length];
        for(int i = 0; i < arr.length;
i++){ dp[i] = 1; for(int j = 0; j < i; j++){ if(arr[j] + 1 == arr[i]){ dp[i] = Math.max(dp[i],dp[j]+1); } } } return dp; } static int[] getLis(int[] arr,int[] dp){ int len = 0; int
index = 0; for(int i = 0; i < dp.length; i++){ if(dp[i] > len){ len = dp[i]; index = i; } } int[] lis = new int[len]; lis[--len] = index; for(int i = index - 1; i >= 0; i--){ if(dp[i] == dp[index] - 1 && arr[i] + 1 == arr[index]){ lis[--len] = i; index = i; } } return lis; } public static void main(String[] args){ Scanner cin = new Scanner(new BufferedInputStream(System.in)); PrintStream out = System.out; int n = cin.nextInt(); int[] arr = new int[n]; for(int i = 0; i < n; i++) arr[i] = cin.nextInt(); int[] dp = getDp(arr); int[] lisIndex = getLis(arr, dp); out.println(lisIndex.length); for(int i = 0; i < lisIndex.length-1; i++) out.print(lisIndex[i] + 1 + " "); out.println(lisIndex[lisIndex.length-1]+1); } }

這裡需要靈活的應用Map(因為a[i]比較大,所以不用陣列),在O(N)時間內解決:

  • 其實也是dpmap[a[i]]表示的以a[i]結尾的最長連續遞增序列的最長長度。
  • map[arr[i]]的更新是在 map[arr[i] - 1]的基礎上+1的;

然後遍歷map找到最大值即可。最後通過最大長度maxLen和最大值maxValue構造出索引。

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {

    public static void main(String[] args){
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        PrintStream out = System.out;
        int n = cin.nextInt();
        int[] arr = new int[n];
        // map中key: arr[i], value : arr[i]結尾的最長長度
        HashMap<Integer, Integer>hMap = new HashMap<>();
        for(int i = 0; i < n; i++) {
            arr[i] = cin.nextInt();
            if(hMap.get(arr[i]-1) == null)
                hMap.put(arr[i], 1);
            else
                hMap.put(arr[i], hMap.get(arr[i]-1)+1);// 在arr[i] - 1的基礎上更新
        }

        int maxLen = 0; //記錄最長長度
        int maxValue = 0; //最長遞增序列的最大值
        for(Map.Entry<Integer, Integer>entry : hMap.entrySet()){
            if(entry.getValue() > maxLen){
                maxLen = entry.getValue();
                maxValue = entry.getKey();
            }
        }
        int minValue = maxValue - maxLen + 1;// 最長遞增序列的最小值
        out.println(maxLen);
        for(int i = 0; i < arr.length; i++){
            if(minValue == arr[i]){
                out.print((i+1) + " ");
                minValue = arr[i] + 1;
            }
        }
        out.println();
    }
}


Codeforces - 1097B. Petr and a Combination Lock(列舉)

題目連結

題目

給你一個nn個角度,要你順時針或者逆時針旋轉這些角度,問你能不能回到源點( 0角度)。

在這裡插入圖片描述
在這裡插入圖片描述

解析

利用二進位制列舉,列舉2 ^ n所有情況,每種情況計算累加和算出來,如果是0或者360的倍數,就可以回到起點,否則就不能。

關於二進位制列舉子集可以看這裡

下面這兩行在程式碼中是等價的。

sum += arr[i] * ( (cur&(1 << i)) != 0 ? 1 : -1);
sum += arr[i] * ( (1&(cur >> i)) != 0 ? 1 : -1); 
import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        PrintStream out = System.out;
        int n = cin.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++)
            arr[i] = cin.nextInt();
        boolean ok = false;
        for (int cur = 0; cur < (1 << n); cur++) {
            int sum = 0;
            for (int i = 0; i < n; i++)
//                sum += arr[i] * ( (cur&(1 << i)) != 0 ? 1 : -1);
                sum += arr[i] * ((1 & (cur >> i)) != 0 ? 1 : -1); // 和上面一行等價
            if (sum % 360 == 0) {
                ok = true;
                break;
            }
        }
        out.println(ok ? "YES" : "NO");
    }
}

也可以遞迴列舉所有的可能:

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class Main {

    static boolean recur(int[] arr, int i, int sum){
        if(i == arr.length)
            return sum % 360 == 0 ? true : false;
        return recur(arr, i+1, sum+arr[i]) || recur(arr, i+1, sum-arr[i]);
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        PrintStream out = System.out;
        int n = cin.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++)
            arr[i] = cin.nextInt();
        boolean ok = recur(arr, 0,0);
        out.println(ok ? "YES" : "NO");
    }
}