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;
}

posted on 2024-07-21 18:13  WHUStar  阅读(2)  评论(0编辑  收藏  举报