zoukankan      html  css  js  c++  java
  • HDU 6049 17多校2 Sdjpx Is Happy(思维题difficult)

    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].
     
    启发博客:http://www.cnblogs.com/FxxL/p/7253028.html
    题意: 给出n,一个1~n的排列,要求进行三步操作
               1.分区(随便分)
               2.对分好的每一个区内进行从小到大的排序
               3.挑选两个区进行交换(只能挑选两个,只能交换易次),使得序列的顺序变成1-n;
              问在满足要求的情况下,最多能分成多少区
    题解:第一步是分区,第二步是枚举。
              分区是开了一个f[i][j]数组用来记录,i-j区间里可以有多少满足要求的段,用到mx,mi,r来辅助,具体可见代码注释。
              枚举是枚举要交换的两个区间,每次更新答案的最大值。设左右区间分别为seg_a,seg_b。
              seg_a要满足:第一段或者之前包括1~i-1的所有数字,当然自身不能为空
                                    把这个区间最大的数定义为k,根据k来枚举seg_b,k是seg_b的右端点
                                    还需满足k==n或者k+1及以后的所有数字包含k+1~n
              seg_b要满足:k是seg_b的右端点,自身不为空,要保证它的最小值是i
              像上述这样来做即可,当然中间会有一些不小心造成的WA点,大家注意即可
     
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 using namespace std;
     6 #define MAXN 3005
     7 
     8 int a[MAXN],res,n;
     9 int mi[MAXN][MAXN],mx[MAXN][MAXN];
    10 //mi[i][j]表示从i到j的最小值,mx[i][j]表示从i到j的最大值
    11 int f[MAXN][MAXN],r[MAXN];
    12 //f[i][j]表示从i到j可以分成的区间数,r[i]表示最近一次从i开始的区间的右端(方便更新)
    13 
    14 
    15 void init()//第一步,分块
    16 {
    17     memset(mi,0,sizeof(mi));
    18     memset(mx,0,sizeof(mx));
    19     memset(f,0,sizeof(f));
    20     memset(r,0,sizeof(r));
    21     for(int i=1;i<=n;i++)
    22     {
    23         mi[i][i]=a[i];
    24         mx[i][i]=a[i];
    25         f[i][i]=1;
    26         r[i]=i;
    27     }
    28     //为mi,mx赋值
    29     for(int i=1;i<=n;i++)
    30     for(int j=i+1;j<=n;j++)
    31     {
    32         mx[i][j]=max(a[j],mx[i][j-1]);
    33         mi[i][j]=min(a[j],mi[i][j-1]);
    34     }
    35     //为f数组赋值
    36     for(int t=2;t<=n;t++)//t在枚举区间长度
    37     for(int i=1;i+t-1<=n;i++)
    38     {
    39         int j=i+t-1;
    40         //不是连续的一段无法分区间
    41         if(mx[i][j]-mi[i][j]!=t-1)
    42             f[i][j]=0;
    43         else
    44         {
    45             //j一定大于r[i]
    46             if(mi[i][r[i]]>mi[i][j])
    47                 f[i][j]=1;
    48             else
    49                 f[i][j]=f[i][r[i]]+f[r[i]+1][j];
    50             r[i]=j;//这个r数组很精华
    51         }
    52     }
    53 }
    54 
    55 void solve()//第二步,枚举找交换区间
    56 {
    57     int k;
    58     res=max(1,f[1][n]);//WA点,一开始写成res=1就WA了
    59     //先枚举seg_a
    60     for(int i=1;i<=n;i++)
    61     for(int j=i;j<=n;j++)
    62     {
    63         //满足条件才能继续枚举seg_b
    64         if(i==1||(f[1][i-1]!=0&&mi[1][i-1]==1))
    65         {
    66             k=mx[i][j];
    67             if(f[i][j]&&(k==n||(f[k+1][n]!=0&&mx[k+1][n]==n)))
    68             {
    69                 for(int t=j+1;t<=k;t++)
    70                 {
    71                     if(f[t][k]&&mi[t][k]==i)
    72                     {
    73                         //printf("%d %d %d %d %d
    ",i,j,t,k,f[1][i-1]+1+f[j+1][t-1]+1+f[k+1][n]);
    74                         res=max(res,f[1][i-1]+1+f[j+1][t-1]+1+f[k+1][n]);
    75                     }
    76                 }
    77             }
    78         }
    79     }
    80 }
    81 
    82 int main()
    83 {
    84     int T;
    85     scanf("%d",&T);
    86     while(T--)
    87     {
    88         scanf("%d",&n);
    89         for(int i=1;i<=n;i++)
    90             scanf("%d",&a[i]);
    91         init();
    92         solve();
    93         printf("%d
    ",res);
    94     }
    95     return 0;
    96 
    97 }
                 
     
  • 相关阅读:
    关于Vue修改默认的build文件存放的dist路径
    JSON.stringify的三个参数(转载)
    JS获取字符串实际长度(包含汉字)的简单方法
    JSON.stringify() 和 JSON.parse()
    iPhone各种机型尺寸、屏幕分辨率
    jquery each 遍历
    React 內联式样
    组件Refs(操作DOM的2⃣️两种方法)
    可复用组件
    事件与数据的双向绑定
  • 原文地址:https://www.cnblogs.com/Annetree/p/7272259.html
Copyright © 2011-2022 走看看