1. 程式人生 > 實用技巧 >Codeforces Round #658 (Div. 2)D(01揹包)

Codeforces Round #658 (Div. 2)D(01揹包)

題:https://codeforces.com/contest/1382/problem/D

題意:給定隨意倆個數組的合併規則,每次取倆個數組第一個的最小值,直至倆陣列為空.。給定目標陣列(1~n出現1次)問能不能2個數組合併成目標陣列

分析:可以把目標陣列分成若干段,要是能每段都連續給到且某些段能剛好湊成n的大小,那麼問題就可以解決;

   而要達到“每段連續給到”:遍歷目標陣列取“連續降序段”。

   而要達到“某些段能剛好湊成n的大小”:對“連續降序段”的大小進行01揹包,看dp[n]是不是恰好為n。

#include<bits/stdc++.h>
using
namespace std; #define pb push_back #define MP make_pair typedef long long ll; typedef unsigned long long ull; const int mod=998244353; const int inf=0x3f3f3f3f; const ll INF=1e18; const int M=4e3+3; int dp[M],a[M],w[M]; int main(){ int t; scanf("%d",&t); while(t--){ int n; scanf(
"%d",&n); for(int i=0;i<=n;i++) dp[i]=0; for(int i=1;i<=2*n;i++) scanf("%d",&a[i]); int maxx=a[1]; int countt=1,tot=0; for(int i=2;i<=2*n;i++){ if(maxx>a[i])countt++; else{ w[tot++]=countt; countt
=1; maxx=a[i]; } } w[tot++]=countt; sort(w,w+tot); for(int i=0;i<tot;i++) for(int j=n;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+w[i]); if(n==dp[n]) puts("YES"); else puts("NO"); } return 0; }
View Code