Codeforces - 977F. Consecutive Subsequence( Map + DP) & 1097B. Petr and a Combination Lock(列舉)
阿新 • • 發佈:2019-01-13
Codeforces - 977F. Consecutive Subsequence( Map + DP) & 1097B. Petr and a Combination Lock(列舉)
- Codeforces - 977F. Consecutive Subsequence( Map + DP)
- Codeforces - 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)
時間內解決:
- 其實也是
dp
,map[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(列舉)
題目連結
題目
給你一個n
和n
個角度,要你順時針或者逆時針旋轉這些角度,問你能不能回到源點( 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");
}
}