您的位置:首页 > 移动开发

hdu 6049 Sdjpx Is Happy(区间DP+暴力枚举)

2017-07-30 18:35 435 查看


Sdjpx Is Happy

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 416    Accepted Submission(s): 170


Problem Description

Sdjpx is a powful man,he controls a big country.There are n soldiers numbered 1~n(1<=n<=3000).But there is a big problem for him.He wants soldiers sorted in increasing order.He find a way to sort,but there three rules to obey.

1.He can divides soldiers into K disjoint non-empty subarrays.

2.He can sort a subarray many times untill a subarray is sorted in increasing order.

3.He can choose just two subarrays and change thier positions between themselves.

Consider A = [1 5 4 3 2] and P = 2. A possible soldiers into K = 4 disjoint subarrays is:A1 = [1],A2 = [5],A3 = [4],A4 = [3 2],After Sorting Each Subarray:A1 = [1],A2 = [5],A3 = [4],A4 = [2 3],After swapping A4 and A2:A1 = [1],A2 = [2 3],A3 = [4],A4 = [5].

But he wants to know for a fixed permutation ,what is the the maximum number of K?

Notice: every soldier has a distinct number from 1~n.There are no more than 10 cases in the input.

 

Input

First line is the number of cases.

For every case:

Next line is n.

Next line is the number for the n soildiers.

 

Output

the maximum number of K.

Every case a line.

 

Sample Input

2
5
1 5 4 3 2
5
4 5 1 2 3

 

Sample Output

4
2
Hint
Test1:
Same as walk through in the statement.
Test2:
[4 5] [1 2 3]
Swap the 2 blocks: [1 2 3] [4 5].

题意:给一个序列,问最多能分成多少组,组内排序后,可以交换两个组的顺序,使整个序列升序;

解:首先处理出一段区间是否合法,即最大值-最小值==区间长度,合法即为1,然后计算出一段区间最多能分成几组;

暴力枚举出两个可能交换顺序的区间,一共2种情况 (1)当前区间是第一段但是最小值不为1,找到这段区间最大值得位置,如果他的右边合法且最大值为n则

枚举左边界直到最小值为1;(2)这段区间不在第一段,但是左边界最小值为1即左边合法,按照(1)的方法找要交换的位置

解题报告

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<map>
#include <bits/stdc++.h>
using namespace std;
const int N = 3000+10;
typedef long long LL;
const LL mod = 1e9+7;
int dp

, save
,mn

,mx

, a
;
int n;
void init()
{
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
dp[i][i]=1,mn[i][i]=mx[i][i]=a[i],save[i]=i;
for(int i=1; i<=n; i++)
{
for(int j=i+1; j<=n; j++)
{
mn[i][j]=min(mn[i][j-1],a[j]);
mx[i][j]=max(mx[i][j-1],a[j]);
}
}
for(int l=2; l<=n; l++)
{
for(int i=1; i+l-1<=n; i++)
{
int j=i+l-1;
if(mx[i][j]-mn[i][j]+1!=l) dp[i][j]=0;
else
{
int k=save[i];
if(mn[i][k]>mn[i][j]) dp[i][j]=1;
else dp[i][j]=dp[i][k]+dp[k+1][j];
save[i]=j;
}
}
}
}
int solve()
{
int ans=max(1,dp[1]
);
for(int i=1; i<=n; i++)
{
for(int j=i; j<=n; j++)
{
if(dp[i][j]&&(i==1||(dp[1][i-1]&& mn[1][i-1]==1)))
{
int k=mx[i][j];
if(k==n||(mx[k+1]
==n&&dp[k+1]
))
{
for(int t=j+1;t<=k;t++)
{
if(dp[t][k]&&mn[t][k]==i)
{
ans=max(ans,dp[1][i-1]+1+dp[j+1][t-1]+1+dp[k+1]
);
}
}
}
}
}
}
return ans;
}

int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
init();
printf("%d\n",solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: