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

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[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;
}









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值