DP+思维
Codeforces Round #765 (Div. 2) C
因为期末考试,很久没有打题了,这是寒假复健训练外加dp苦手的救赎
题意:
给n个限速牌,每个限速牌写上ai,表示经过本限速牌后今后每公里限制走ai单位的时间。
再给定每个牌的位置。
求至多去除k个牌能花的最短时间
其中不可以去除在位置0处的第一个牌,因为它给定了初始速度
解法:
起初想的贪心暴力过,但是不太行,就当练习链表了
然后是dp
考虑dp[i][j]表示从第i个牌子开始走到最后,切掉j个牌儿(不包括自己)花的最短时间
丢脸:
因为每个牌走到终点花的时间是依赖后面的牌子的,所以从尾到头遍历第一层
然后根据当前的起点牌,枚举拆了几个牌后,到了下一个没有被拆掉的牌,这样可以包含所有的方案
#include<bits./stdc++.h>
#define ll long long
#define mes(a,b) memset(a,b,sizeof(a))
#define ctn continue
#define ull unsigned long long
#pragma warning(disable:4996)
#define tgg cout<<"---------------"<<endl;
const ll linf = 9223372036854775807;
const int inf = 0x3f3f3f3f;
using namespace std;
const double pi = acos(-1);
const ll maxn = 2e5 + 4;
const int mod = 31011;
const double eps = 1e-8;
const ull p = 131;
const ull pc = 13331;
inline ll gcd(int a, int b) {
while (b ^= a ^= b ^= a %= b);
return a;
}
int pos[502];
int val[502];
int dp[502][502];// 第i个牌子开始拆j个牌子最短时间
int main() {
mes(dp, inf);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> pos[i];
}
for (int i = 1; i <= n; i++) {
cin >> val[i];
}
pos[n + 1] = m;
dp[n + 1][0] = 0;
// 从尾到头遍历牌
for (int i = n; i >= 1; i--) {
// 今后拆掉j个牌,最多n-i个
for (int j = 0; j <= n - i; j++) {
// 假设第l个牌是第一个没有被拆的牌,那么前面全拆
for (int l = 0; l <= j; l++) {
dp[i][j] = min(dp[i][j], val[i] * (pos[i + l + 1] - pos[i]) + dp[i + l + 1][j - l]);
}
}
}
int ans = inf;
for (int i = 0; i <= k; i++) {
ans = min(ans, dp[1][i]);
}
cout << ans << endl;
return 0;
}