zoukankan      html  css  js  c++  java
  • 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
    ", ++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
    ", floor(dfs(i, i, 0) + ssum)) ;
                break ;
            }
        }
        return 0 ;
    }
    
  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/harryhqg/p/Blocks-FixingtheGreatWall.html
Copyright © 2011-2022 走看看