zoukankan      html  css  js  c++  java
  • CF1381B Unmerge

    CF1381B Unmerge

    洛谷传送门

    题目翻译

    对于一个长度为(2n)的排列(排列是指一个没有重复元素,有顺序的正整数集合)(保证(n)为正整数),问:

    是否可以把这个排列分解成两个长度为(n)的队列,使得每次取出两个队列的较小队首后,恰好能还原成原来的排列。如果可以,输出(YES),否则输出(NO)

    输入格式

    第一行包括一个整数(tquad(1le tle 1000)),表示测试数据的组数。接下来的(2t)行为测试数据。

    每组测试数据的第一行包含一个整数(n),意义如题所示。

    每组测试数据的第二行包含一个长度为(2n)的排列(p)

    数据保证:所有测试数据的(n)的和不超过(2000).

    输出格式

    对于每组数据,如果可以,输出(YES),否则输出(NO)

    说明/提示

    第一组数据,有:$[2,3,1,4]=merge([3,1],[2,4]) $。

    第二组数据,我们可以看到([3,1,2,4])为什么不能被合法分解。

    第三组数据,有:([3,2,6,1,5,7,8,4]=merge([3,2,8,4],[6,1,5,7]))

    第四组数据 ,有:([1,2,3,4,5,6]=merge([1,3,6],[2,4,5]))


    自己翻译的,不知道能不能过。

    一看到这种数列的题首先想到研究性质。手画几组样例发现,如果一个排列的最大值在这个排列的前(n)项出现,那么这个排列就肯定是废废了,因为这个最大值是出不来的,也就无法构造出这个排列。

    然鹅这个性质好像并没有什么用处。这里仅作为思路展示来使用。

    然后我们在进一步思考的时候,发现一个问题:对于某一个极大值来讲,从它开始到下一个比它大的值必须要在一个队列里连续排列。

    就拿这组样例说话:

    3 2 6 1 5 7 8 4
    

    如果3在第一个队列里了,那么2肯定也在同一个队列里并且紧随其后,才可能保证3,2连续被弹出,否则,如果3在第一个队列,2在第二个队列,那么一开始弹出的就不是3而是2,如果2在6后面,在6没有被弹出之前也不可能轮到2,构造均宣布失败。

    那么,这么一个数列就被我们分成了若干个小段,每段由一个段首极大值和在它后面的若干个较小值组成。比如上面的例子,最终我们就将其分成了如下的段落:

    [3,2],[6,1,5],[7],[8,4]
    

    到了这里就容易想到:如果我们能从这些长度不同的段落中挑出任意段,使之恰好能塞满长度(n)的一个排列,那么我们就构造成功了。(题目不需要我们考虑段与段之间的顺序问题)比如上面的样例答案就是:

    [3,2,8,4],[6,1,5,7]
    

    所以好像是个背包问题?

    还是最容易的0/1背包。

    所以我们只需要统计出所有的段落长度,然后来跑0/1背包即可。状态就定义为:(dp[i][j])表示前(i)个物品能否装满容量为(j)的背包。一个到达性的背包问题。自然可以想到,如果(dp[i-1][j])或者(dp[i-1][j-len[i]])(其中(len[i])表示第(i)段的长度)可以到达,那么(dp[i][j])就是可以到达的。

    答案就是(dp[tot][n]),可达就是(YES),否则就是(NO)

    兴冲冲地写完代码,T了。(逃

    后来一看,发现自己狂开了三个(memset)。(绝不能开,开了就T)仔细思考后,发现保存原数列的(a)数组和每段的长度(len)都不需要清空,反正也是被覆盖,没被覆盖的地方也用不上。不影响转移。

    那么(dp)数组呢?如果依然(memset)或者手动清空的话还是会T啊。

    考虑边转移边清空,我们只需要把初值(dp[0][0])设置成1,之后转移之前把(dp[i][j])先清掉,就能保证转移的有序正确性。

    那么有了代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int t,n,maxx,tmp,cnt,maxpos,tot;
    int len[4010],a[4010];
    int dp[4010][2010];//dp[i][j]表示前i个物品能否装满体积为j的背包。
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int read()
    {
        int x=0,f=1;
        char ch=nc();
        while(ch<'0'||ch>'9')
            if(ch=='-')
                f=-1,ch=nc();
        while(ch>='0'&&ch<='9')
            x=x*10+ch-48,ch=nc();
        return x*f;
    }
    int main()
    {
        t=read();
        while(t--)
        {
            tot=0,maxx=0;
            n=read();
            for(int i=1;i<=2*n;i++)
            {
                a[i]=read();
                if(a[i]>maxx)
                    maxx=a[i],maxpos=i;
                if(i==1)
                    tmp=a[i],cnt=1;
                if(a[i]>tmp)
                    len[++tot]=cnt,tmp=a[i],cnt=1;
                if(a[i]<tmp)
                    cnt++;
            }
            if(maxpos<n)
            {
                puts("NO");
                continue;
            }
            len[++tot]=cnt;
            dp[0][0]=1;
            for(int i=1;i<=tot;i++)
                for(int j=0;j<=n;j++)
                {
                    dp[i][j]=0;
                    if(j>=len[i])
                        dp[i][j]|=dp[i-1][j-len[i]];
                    dp[i][j]|=dp[i-1][j];
                }
            if(dp[tot][n])
                puts("YES");
            else
                puts("NO");
        }
        return 0;
    }
    
  • 相关阅读:
    跟我一起学Go系列:gRPC 全局数据传输和超时处理
    跟我一起学Go系列:Go gRPC 安全认证方式-Token和自定义认证
    c++中的继承关系
    数值型模板参数的应用
    [源码解析] 机器学习参数服务器Paracel (3)------数据处理
    [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader
    [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampler
    [源码解析] 机器学习参数服务器 Paracel (2)--------SSP控制协议实现
    [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构
    [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13375485.html
Copyright © 2011-2022 走看看