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

来源:互联网 发布:写c语言用什么软件 编辑:程序博客网 时间:2024/04/27 06:28

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
251 5 4 3 254 5 1 2 3
 

Sample Output
42
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[N][N], save[N],mn[N][N],mx[N][N], a[N];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][n]);    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]==n&&dp[k+1][n]))                {                    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][n]);                        }                    }                }            }        }    }    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;}









原创粉丝点击