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

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxzxzx0119/article/details/86354103

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");
    }
}

猜你喜欢

转载自blog.csdn.net/zxzxzx0119/article/details/86354103