Blocks && Fixing the Great wall

读完大概都能发现是dp

方法都很套路

首先第一个题每次取的是一段区间,就能够想到区间dp

按照区间dp的模板能够想到一种裸的方法:

\(dp[i][j]\) 表示处理完 \([i...j]\) 的最大分数

然后你会发现这种方法连样例1都不能搞定

因为 \(dp[i][j]\) 可能受到后面一些同色块的影响,导致直接处理不能获得最优值

那怎么办?

哪有问题就解决哪里

添加一位 \(k\), 表示 区间右还有与块 \(j\) 颜色相同的 \(k\) 个块

怎么转移?

  1. 直接把 \([j,j+k]\) 这段区间领出来处理分数
  2. 找到 \(j\) 之前的一个与 \(j\) 颜色相同的块,然后把 \([p+1,j]\) 剖出来,剩下 \([i,p,k+1]\) 接着 \(dp\)

实现可以采用线性或者记忆化

int n, Case ;
int col[N], hd[N], nxt[N] ;
ll dp[N][N][N] ;

ll dfs(int i, int j, int k) {
    if (i > j) return 0 ;
    if (dp[i][j][k] >= 0) return dp[i][j][k] ;
    ll& ans = dp[i][j][k] ;
    ans = dfs(i, j - 1, 0) + (k + 1) * (k + 1) ;
    for (int p = nxt[j]; p >= i; p = nxt[p])
    chmax(ans, dfs(i, p, k + 1) + dfs(p + 1, j - 1, 0)) ;
    return ans ;
}

signed main() {
    int T ; scanf("%d", &T) ;
    while (T--) {
        ass(dp, -1) ; clr(nxt) ; clr(hd) ;
        scanf("%d", &n) ;
        rep(i, 1, n) {
            scanf("%d", &col[i]) ;
            nxt[i] = hd[col[i]] ;
            hd[col[i]] = i ;
        }
        printf("Case %d: %lld\n", ++Case, dfs(1, n, 0)) ;
    }
    return 0 ;
}

第二个题就更套路了,我怎么记得我做过这个题

好像是关路灯吧我也忘记了

有一个结论是,把这些缺口排成一排,不可能先走过这个点不修走过去,然后又走回来修,这样肯定是不优的

换句话说,就是修的段肯定是一个连续的区间

配合数据范围提示能够想到区间 \(dp\)

\(dp[i][j][0/1]\) 表示 当前处理了区间 \([i...j]\),当前在 \(i\)\(j\) 的 方案数的最小代价

\(dp[l][r][0]=min(dp[l-1][r][0]+len(l-1,l)/v*cost, dp[l][r+1][1]+len(l,r+1)/v*cost)\)
\(dp[l][r][1]=min(dp[l-1][l][0]+len(l-1,r)/v*cost, dp[l][r+1][1]+len(r,r+1)/v*cost)\)

\(cost\) 就是这一段走的代价,可以通过前缀和处理

注意将开始节点也塞进去,\(n+1\) 个点进行 $dp $

orz you


struct node {
    double pos, c, del ;
    bool operator < (const node &a) const {
        return pos < a.pos ;
    }
} a[N] ;

int n, v, x ;
double sum[N], dp[N][N][2] ;

double dfs(int ll, int rr, int d) {
    if (ll == 1 && rr == n + 1) return 0 ;
    if (dp[ll][rr][d] != iinf) return dp[ll][rr][d] ;
    double resl = 0, resr = 0, w = sum[n + 1] - (sum[rr] - sum[ll - 1]) ;
    if (ll > 1) {
        if (d == 1) resl = (a[rr].pos - a[ll - 1].pos) / v * w ;
        else resl = (a[ll].pos - a[ll - 1].pos) / v * w ;
    }
    if (rr <= n) {
        if (d == 1) resr = (a[rr + 1].pos - a[rr].pos) / v * w ;
        else resr = (a[rr + 1].pos - a[ll].pos) / v * w ;
    }
    if (ll > 1) chmin(dp[ll][rr][d], dfs(ll - 1, rr, 0) + resl) ;
    if (rr <= n) chmin(dp[ll][rr][d], dfs(ll, rr + 1, 1) + resr) ;
    return dp[ll][rr][d] ;
}

int main() {
    while (scanf("%d%d%d", &n, &v, &x) != EOF && n && v && x) {
        double ssum = 0 ;
        rep(i, 1, n) scanf("%lf%lf%lf", &a[i].pos, &a[i].c, &a[i].del) ;
        a[n + 1] = (node) {x, 0, 0} ;
        sort(a + 1, a + n + 2) ;
        rep(i, 1, n + 1) ssum += a[i].c, sum[i] = sum[i - 1] + a[i].del ;
        rep(i, 1, n + 1)
        rep(j, 1, n + 1)
        dp[i][j][0] = dp[i][j][1] = iinf ;
        rep(i, 1, n + 1)
        if (a[i].pos == x) {
            printf("%.0lf\n", floor(dfs(i, i, 0) + ssum)) ;
            break ;
        }
    }
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/harryhqg/p/Blocks-FixingtheGreatWall.html
今日推荐