• 【BZOJ】3971 [WF2013]Матрёшка


    【算法】区间DP

    【题解】

    参考写法:BZOJ 3971 Матрёшка 解题报告

    第二个DP可以预处理mex优化到O(nM+n2),不过我懒……

    第一个DP有另一种写法:不预处理,在一个n2取出来的的区间中,枚举决策点从左到右时,保留左最小值的可保留数不严格单调递增,保留右最小值的可保留数不严格单调递减,均摊O(1)。

    ???
    【细节】

    f[0]=0初始化

    inf+inf+inf就会爆int

    区间第二重循环是i=1...n-p,否则有可能爆数组边界。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=510,inf=0x3f3f3f3f;
    int dp[maxn][maxn],f[maxn],sum[maxn][maxn],ms[maxn][maxn],n,m,A[maxn];
    int calc(int a,int b,int c,int d)
    {
        int m1=ms[a][b],m2=ms[c][d];
        int ans=inf;
        ans=(b-a+1)-(sum[b][m2]-sum[a-1][m2])+(d-c+1);
        ans=min(ans,(d-c+1)-(sum[d][m1]-sum[c-1][m1])+(b-a+1));
        return ans;
    }
    bool B[maxn];
    bool mex(int a,int b)
    {
        memset(B,0,sizeof(B));
        for(int i=a;i<=b;i++)if(B[A[i]])return 0;else B[A[i]]++;
        bool ok=0;
        if(!B[1])return 0;
        for(int i=1;i<=m;i++)
        {
            if(ok&&B[i])return 0;
            if(B[i-1]&&!B[i])ok=1;
        }
        return 1;
    }
    int main()
    {
        scanf("%d",&n);
        m=0;
        for(int i=1;i<=n;i++){scanf("%d",&A[i]);m=max(m,A[i]+1);}
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=A[i];j++)sum[i][j]=sum[i-1][j];
            for(int j=A[i];j<m;j++)sum[i][j]=sum[i-1][j]+1;
            ms[i][i]=A[i];
            for(int j=i+1;j<=n;j++)ms[i][j]=min(ms[i][j-1],A[j]);
        }
        for(int p=1;p<=n-1;p++)
        {
            for(int i=1;i<=n-p;i++)//
            {
                int j=i+p;
                dp[i][j]=inf;
                for(int k=i;k<j;k++)if(dp[i][k]<inf&&dp[k+1][j]<inf)//
                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+calc(i,k,k+1,j));
            }
        }
        memset(f,0x3f,sizeof(f));
        f[0]=0;//初始化!!! 
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<i;j++)if(f[j]<inf-100)
            {
                if(mex(j+1,i))
                {
                    f[i]=min(f[i],f[j]+dp[j+1][i]);
                }
            }
        }
        if(f[n]>inf-100)printf("Impossible");
        else printf("%d",f[n]);
        return 0;
    }
    View Code
  • 相关阅读:
    leetcode1030之距离顺序排列矩阵单元格
    leetcode56之合并区间
    leetcode976之三角形最大周长
    leetcode922----按奇偶排序数组
    leetcode198之打家劫舍问题
    leetcode350之实现求解两数组交集(包含重复元素)
    【Python错误】日常记录(持续更新)
    【JavaScript】Lodash在React Native中的使用
    【Python】BeautifulSoup的使用
    转载【Python】python正则表达式详解
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6925777.html
Copyright © 2020-2023  润新知