dls的区间dp

区间dp

ICPC Beijing 2017 J, Pangu and Stones

题目链接:http://oj.daimayuan.top/course/8/problem/327 题目大意:有n堆石子,每对有ai个,每次可以合并[L, R]堆石子,代价是这些石子的之和 f[l][r][k]:表示将l,r合并成k堆的最小代价 划分方式:根据最后一顿划分的分界线在哪里 f[l][r][1]:表示合并成一堆的代价,我们利用前面的计算的f[l][r][k]的k是否在L-R之间在进行真正的代价合并 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N = 110; const LL inf = 1ll<<60; int a[N], s[N]; LL f[N][N][N]; int main(){ int n, L, R; while(scanf("%d %d %d", &n , &L, &R) == 3){ for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); for(int i = 1; i <= n; i ++) s[i] = s[i-1] + a[i]; for(int i = 1; i <= n; i ++){ for(int j = 1; j <= n; j ++){ for(int k = 1; k <= n; k ++){ f[i][j][k] = inf; } } } for(int len = 1; len <= n; len ++){ for(int l = 1; l + len - 1 <= n; l ++){ int r = l + len - 1; // 边界,一般边界写好了,下面按照思路正常进行dp就可以了 if(len == 1) f[l][r][1] = 0; else{ // 合并其实并没有发生在枚举mid那里,mid哪里只是找把l,r变成k堆的最小代价 // 而是k这个循环的最后,才真正的将l,r合并起来 for(int k = 2; k <= n; k ++){ for(int mid = l; mid < r; mid ++){ f[l][r][k] = min(f[l][r][k], f[l][mid][1] + f[mid+1][r][k-1]); } if(k >= L && k <= R) f[l][r][1] = min(f[l][r][1], f[l][r][k] + s[r] - s[l-1] ); } } } } if(f[1][n][1] <= (1ll<<60)/2) printf("%lld\n", f[1][n][1]); else puts("0"); } return 0; }

ICPC Kunming 2020 C, Cities

题目链接:http://oj.daimayuan.top/course/8/problem/327 题目大意:给定一个长度为n(<=5000)的序列,每次可以选择一段连续相等的序列把它变成另外一个数,问使该序列变成相同的最少操作次数,每个数出现的次数不超过15 f[l][r]表示将l,r合并成相同的最小代价的话 那么我们需要枚举和a[l]相等的其他位置,如果这个位置是r的话,显然我们可以用f[l+1][r]来更新f[l][r] 如果相等的位置是在中间的话,我们可以发现一个性质,一定存在一种替换方案,使得al...ar变成al并且次数是最小的,所以现在的结果直接用f[l][p]+f[p][r]更新就可以了,我们把他们都染成a[l]这个数字 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N = 5010, inf = 1<< 29; vector<int> pos[N]; int f[N][N]; int a[N]; int main(){ int T; cin >> T; while(T--){ int n; cin >> n; for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); pos[a[i]].clear(); } for(int i = 1; i <= n; i++){ pos[a[i]].push_back(i); } for(int len = 1; len <= n; len ++){ for(int l = 1; l + len - 1 <= n; l ++){ int r = l + len - 1; f[l][r] = inf; } } for(int len = 1; len <= n; len ++){ for(int l = 1; l + len - 1 <= n; l ++){ int r = l + len - 1; if(len == 1) f[l][r] = 0; else{ f[l][r] = f[l+1][r] + 1; for(auto p : pos[a[l]]){ if(p > r) break; if(p <= l) continue; if(p == r) f[l][r] = min(f[l][r], f[l+1][r]); else f[l][r] = min(f[l][r], f[l+1][p] + f[p][r] ); } } } } printf("%d\n", f[1][n]); { } return 0; }

__EOF__

本文作者njw1123
本文链接https://www.cnblogs.com/njw1123/p/15993315.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   牛佳文  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示