洛谷-P2254 瑰丽华尔兹
作者:互联网
瑰丽华尔兹
\(dp\) + 单调队列优化
\(dp[k][i][j]\) 表示在第 \(k\) 次倾斜后 \(x = i\) 且 \(y = j\) 的位置上,能够滑动的最长距离,第一纬可以直接用滚动数组消除
显然每次倾斜都要对所有的状态进行更新,分四个方向进行更新,以向右滑动为例,有状态转移方程:
\[dp[i][j] = \max_{k=t-j}^{j}(dp[i][k]+j-k) \]\(t\) 表示这次倾斜持续的时长
使用这样的转移,算法时间复杂度为 \(O(Tn^3)\),显然不是我们能接受的
考虑相同方向,相邻的位置都是从几乎重叠的区间转移过来,且满足单调,因此考虑是用单调队列来进行优化
\[dp[i][j] = \max_{k=t-j}^{j}(dp[i][k]-k) + j \]优化后,算法时间复杂度为 \(O(Tn^2)\)
#include <iostream>
#include <cstdio>
#include <stack>
#include <deque>
#include <string>
using namespace std;
#define pii pair<int, int>
const int maxn = 210;
const int inf = 0x3fffffff;
string s[maxn];
int dp[maxn][maxn];
int main()
{
int n, m, x, y, k;
cin >> n >> m >> x >> y >> k;
for(int i=0; i<n; i++)
cin >> s[i];
for(int i=0; i<=n; i++)
for(int j=0; j<=m; j++)
dp[i][j] = -inf;
x--;
y--;
dp[x][y] = 0;
while(k--)
{
int a, b, op;
cin >> a >> b >> op;
int t = b - a + 1;
if(op == 1)
{
for(int j=0; j<m; j++)
{
deque<pii>q;
for(int i=n-1; i>=0; i--)
{
if(s[i][j] == 'x')
while(q.size()) q.pop_front();
while(q.size() && q.back().first <= dp[i][j] - n + i)
q.pop_back();
q.push_back({dp[i][j] - n + i, i});
while(q.front().second > i + t) q.pop_front();
dp[i][j] = q.front().first + n - i;
}
}
}
else if(op == 2)
{
for(int j=0; j<m; j++)
{
deque<pii>q;
for(int i=0; i<n; i++)
{
if(s[i][j] == 'x')
while(q.size()) q.pop_front();
while(q.size() && q.back().first <= dp[i][j] - i)
q.pop_back();
q.push_back({dp[i][j] - i, i});
while(q.front().second < i - t) q.pop_front();
dp[i][j] = q.front().first + i;
}
}
}
else if(op == 3)
{
for(int i=0; i<n; i++)
{
deque<pii>q;
for(int j=m-1; j>=0; j--)
{
if(s[i][j] == 'x')
while(q.size()) q.pop_front();
while(q.size() && q.back().first <= dp[i][j] - m + j)
q.pop_back();
q.push_back({dp[i][j] - m + j, j});
while(q.front().second > j + t) q.pop_front();
dp[i][j] = q.front().first + m - j;
}
}
}
else if(op == 4)
{
for(int i=0; i<n; i++)
{
deque<pii>q;
for(int j=0; j<m; j++)
{
if(s[i][j] == 'x')
while(q.size()) q.pop_front();
while(q.size() && q.back().first <= dp[i][j] - j)
q.pop_back();
q.push_back({dp[i][j] - j, j});
while(q.front().second < j - t) q.pop_front();
dp[i][j] = q.front().first + j;
}
}
}
}
int ans = -inf;
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
ans = max(ans, dp[i][j]);
cout << ans << endl;
return 0;
}
标签:华尔兹,洛谷,int,P2254,while,front,include,dp,size 来源: https://www.cnblogs.com/dgsvygd/p/16482766.html