• 【NOI2019】机器人


    题面

    https://www.luogu.org/problem/P5469

    题解

    这里,我们只考虑$50pts$的区间$dp$做法。

    因为最大值把区间劈成互不影响的两端,我们可以用类似分治的思想设计$dp$,解决这个问题。

    设$f[l][r][x]$为$[l..r]$的最大值为$x$的方案数,转移的时候直接枚举最大值的位置,让左边的最大值小于等于它,让右边的最大值小于它,即可转移。

    注意这类转移和合并石子不同,并不是两个区间的并,而是左区间并最大值并右区间,这样才能充分利用性质。

    因为对于一个区间,可以取得最大值的位置是很少的,所以用记忆化的搜索优化(这更印证了分治思想)更加优美,可以做到更优秀的复杂度。但是我懒得写了。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ri register int
    #define N 55
    #define H 105
    #define LL long long
    #define mod 1000000007
    
    using namespace std;
    
    inline int read() {
      int ret=0,f=0; char ch=getchar();
      while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
      while (ch>='0' && ch<='9') ret*=10,ret+=ch-'0',ch=getchar();
      return f?-ret:ret;
    }
    
    int n,ans=0;
    int c[N],a[N],b[N];
    int f[N][N][H];
    
    int mul(int x,int y) {
        LL z=x; z*=y;
        return (int)(z%mod);
    }
    int jia(int x,int y) {
        x+=y;
        if (x>=mod) x-=mod;
        return x;
    }
    
    int main() {
      n=read();
      int mb=0;
      for (ri i=1;i<=n;i++) a[i]=read(),b[i]=read(),mb=max(mb,b[i]);
    
      for (ri i=0;i<=n;i++) f[i+1][i][0]=1;
      for (ri i=1;i<=n;i++) {
          for (ri j=a[i];j<=b[i];j++) f[i][i][j]=1;
      }
        for (ri l=1;l<=n-1;l++)
            for (ri lb=1,rb;lb+l<=n;lb++) {
                rb=lb+l;
                int pl,pr;
                if ((lb+rb)%2==1) {
                    pl=(lb+rb)/2;
                    pr=(lb+rb)/2+1;
                }
                else {
                    pl=(lb+rb)/2-1;
                    pr=(lb+rb)/2+1;
                }
                for (ri x=pl;x<=pr;x++) {
                    for (ri h=a[x];h<=b[x];h++) {
                        int s1=0;
                        for (ri j=0;j<=h;j++) s1=jia(s1,f[lb][x-1][j]);
                        int s2=0;
                        for (ri j=0;j<h;j++) s2=jia(s2,f[x+1][rb][j]);
                        f[lb][rb][h]=jia(f[lb][rb][h],mul(s1,s2));
                    }
                }
            }
        int ans=0;
        for (ri i=0;i<=mb;i++) ans=jia(ans,f[1][n][i]);
        cout<<ans<<endl;
    }
  • 相关阅读:
    第一次sprint团队贡献分改
    第一个Sprint冲刺事后诸葛报告
    第一个Sprint冲刺第十天
    第一个Sprint冲刺第九天
    第一个Sprint冲刺第八天
    第一个Sprint冲刺第七天
    第一个Sprint冲刺第六天
    第一个Sprint冲刺第五天
    第一个Sprint冲刺第四天
    第一个Sprint冲刺第三天
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11792603.html
Copyright © 2020-2023  润新知