nssl1488-상승자 서열【욕심,dp】

18706 단어 dp탐욕스럽다

본제


제목의 대의.


길이 nnn의 서열로 두 개의 상승자 서열로 나누려면 길이 차이가 가장 적어야 한다

문제풀이의 방향


우리는 i이후 두 개의 연결 블록이 서로 영향을 주지 않기 때문에 우리는 dpdpdp로 방안을 계산할 수 있다.
계속 최적화를 고려하면 만약에 ii와 jjj 사이에 연결이 있다면 임의의 i방안 수가 2 c n t 2^ {cnt} 2cnt(cnt는 연결 블록 수이기 때문에 연결 블록 수는 l o g(1e 18)log(1e18)log(1e18)log(1e18)log(1e18)를 초과하지 않습니다.

c o d e code code

#include
#include
#include
#include
using namespace std;
const int N=1e5+10,K=300;
int T,n,a[N],maxs[N],mins[N];
int cnt,b[K],e[K],z[K];
bool f[2][N];
stack<int> q1,q2;
int main()
{
	//freopen("sample2.in","r",stdin);
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			maxs[i]=max(maxs[i-1],a[i]);
		}
		mins[n+1]=2147483647/3;cnt=0;
		for(int i=n;i>=1;i--)
			mins[i]=min(mins[i+1],a[i]);
		for(int i=1;i<=n;i++)
			if(maxs[i]<=mins[i+1]||i==n)
				b[++cnt]=e[cnt-1]+1,e[cnt]=i;
		bool flag=0;
		for(int i=1;i<=cnt;i++){
			while(!q1.empty())q1.pop();
			while(!q2.empty())q2.pop(); 
			for(int j=b[i];j<=e[i];j++){
				if(q1.empty()||a[j]>q1.top())q1.push(a[j]);
				else if(q2.empty()||a[j]>q2.top())q2.push(a[j]);
				else{flag=1;break;}
			}
			if(flag)break;
			z[i]=q1.size()-q2.size();
		}
		if(flag){
			printf("-1
"
); continue; } memset(f,0,sizeof(f)); f[0][0]=1; for(int i=1;i<=cnt;i++) for(int j=0;j<=n;j++) f[i&1][j]=f[~i&1][abs(j-z[i])]|f[~i&1][abs(j+z[i])]; for(int j=0;j<=n;j++) if(f[cnt&1][j]){ printf("%d
"
,j); break; } } }

좋은 웹페이지 즐겨찾기