其他分享
首页 > 其他分享> > 洛谷-P2254 瑰丽华尔兹

洛谷-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