E. Rudolf and k Bridges
链接
https://codeforces.com/problemset/problem/1941/E
题目
思路
比较容易想到的一道题(但是之前想了好久hhh)。首先题意是对一连串的桥的代价求和,不难想到是前缀和求区间最小。那么就可以拆分这题为每行处理。容易想到dp,而且dp的过程也比较简单:设dp[i]是到达i的最小代价,那么对∀j∈[i-d-1,i-1],有dp[i]=min(dp[i],dp[j]+depth[j]+1),depth是j位置的水深,加1就是代价. 纯暴力会tle,所以加上单调队列优化。代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#define IOS ios::sync_with_stdio(false), cin.tie(0) ,cout.tie(0)
using namespace std;
#define int long long
const int N = 1e2 + 10;
int height[N];
const int M = 2e5 + 10;
int depth[M];
int cost[M];
int n, m, k, d;
int calculate()
{
for (int i = 1; i <= m; i++)cost[i] = 0;
deque<int>dq;
for (int i = 2; i <= m; i++)
{
if (i <= d + 2)
{
cost[i] = depth[i] + 1;
while (!dq.empty() and cost[dq.back()]>=cost[i])dq.pop_back();
dq.push_back(i);
}
else
{
//单调队列优化
while (!dq.empty() and dq.front() + d + 1 < i)dq.pop_front();
cost[i] = cost[dq.front()] + depth[i] + 1;
while(!dq.empty() and cost[dq.back()] >= cost[i])dq.pop_back();
dq.push_back(i);
}
}
return cost[m] + 1;//加1是因为最后那个岸上也有高度为1
}
signed main()
{
IOS;
int t; cin >> t;
while (t--)
{
cin >> n >> m >> k >> d;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> depth[j];
}
height[i] = calculate();//记录
height[i] += height[i - 1];//前缀和处理
}
int ans = 0x3f3f3f3f3f;
for (int i = 1; i + k <= n + 1; i++)
ans = min(ans, height[i + k - 1] - height[i - 1]);//连续区间的代价和
cout << ans << '\n';
}
return 0;
}