• 单调队列优化dp,k次移动求最长路


    洛谷2254

    给你k次移动

    每次移动给你一个时间段 a,b和方向dir

    地图上有障碍物

    为了不撞上障碍物你可以施法让箱子停下来

    问箱子可以走的最长路

    ((以下是洛谷的题解))

    /*首先考虑对于时间t来dp: f[t][i][j]表示在第t时刻在第i行第j列所能获得的最长距离。

    转移方程:f[t][i][j]=max(f[t-1][i][j],f[t][i*][j*]+1)(i*,j*为上一个合理的位置) 这样时间复杂度为O(TNM),可以过50%,但对于100%TLE且MLE。

    所以必须优化,首先把时间t换成区间k, 令f[k][i][j]表示在第k段滑行区间中在位置i,

    j所能获得最长距离 注意到在第k段时间内只能向某个方向最多走x步(x为区间长度),

    得到转移方程 f[k][i][j]=max(f[k-1][i][j],f[k][i*][j*]+dis(i,j,i*,j*))(i*,j*为上一个合理的位置) 这个做法的时间复杂度是O(kn^3),会超时,

    需要进一步优化 用单调队列优化掉内层的一个n,就可以做到O(kn^2),可以AC,

    本代码中还使用了滚动数组优化 用单调递减队列求最大值时,遇到障碍清空整个队列即可,另外队列比较时需要加上偏移量dis*/

     1 #include<bits/stdc++.h>
     2 #define mp make_pair
     3 #define pb push_back
     4 #define first fi
     5 #define second se
     6 #define pw(x) (1ll << (x))
     7 #define sz(x) ((int)(x).size())
     8 #define all(x) (x).begin(),(x).end()
     9 #define rep(i,l,r) for(int i=(l);i<(r);i++)
    10 #define per(i,r,l) for(int i=(r);i>=(l);i--)
    11 #define FOR(i,l,r) for(int i=(l);i<=(r);i++)
    12 #define eps 1e-9
    13 #define PIE acos(-1)
    14 #define cl(a,b) memset(a,b,sizeof(a))
    15 #define fastio ios::sync_with_stdio(false);cin.tie(0);
    16 #define lson l , mid , ls
    17 #define rson mid + 1 , r , rs
    18 #define ls (rt<<1)
    19 #define rs (ls|1)
    20 #define INF 0x3f3f3f3f
    21 #define LINF 0x3f3f3f3f3f3f3f3f
    22 #define freopen freopen("in.txt","r",stdin);
    23 #define cfin ifstream cin("in.txt");
    24 #define lowbit(x) (x&(-x))
    25 #define sqr(a) a*a
    26 #define ll long long
    27 #define ull unsigned long long
    28 #define vi vector<int>
    29 #define pii pair<int, int>
    30 #define dd(x) cout << #x << " = " << (x) << ", "
    31 #define de(x) cout << #x << " = " << (x) << "
    "
    32 #define endl "
    "
    33 using namespace std;
    34 //**********************************
    35 const int maxn=207;
    36 const int dx[]={0,-1,1,0,0},dy[]={0,0,0,-1,1};
    37 int n,m,X,Y,k;
    38 char pic[maxn][maxn];
    39 int dp[maxn][maxn];
    40 int ans;
    41 struct node{
    42     int id,v;
    43 }que[maxn];
    44 //**********************************
    45 inline bool in(int x,int y)
    46 {
    47     return x>=1&&x<=n&&y>=1&&y<=m;
    48 }
    49 void solve(int x,int y,int len,int dir)
    50 {
    51     int head=1,tail=0;
    52     for(int i=0;in(x,y);++i,x+=dx[dir],y+=dy[dir]){
    53         if(pic[x][y]=='x') head=1,tail=0;
    54         else {
    55             while(head<=tail&&que[tail].v+i-que[tail].id<dp[x][y])tail--;
    56             que[++tail]=node{i,dp[x][y]};
    57             if(que[tail].id-que[head].id>len)++head;
    58             dp[x][y]=que[head].v+i-que[head].id;
    59             ans=max(ans,dp[x][y]);
    60         }
    61     }
    62 }
    63 //**********************************
    64 int main()
    65 {
    66 //    freopen;
    67     ans=0;
    68     scanf("%d %d %d %d %d",&n,&m,&X,&Y,&k);
    69     cl(dp,-INF);dp[X][Y]=0;
    70     FOR(i,1,n)scanf("%s",pic[i]+1);
    71 //    FOR(i,1,n)printf("%s
    ",pic[i]+1);
    72     FOR(i,1,k){
    73         int a,b,dir;
    74         scanf("%d %d %d",&a,&b,&dir);
    75         int len=b-a+1;
    76         if(dir==1)FOR(i,1,m)solve(n,i,len,1);
    77         else if(dir==2)FOR(i,1,m)solve(1,i,len,2);
    78         else if(dir==3)FOR(i,1,n)solve(i,m,len,3);
    79         else if(dir==4)FOR(i,1,n)solve(i,1,len,4);
    80     }
    81 //    de(dp[4][2]);
    82     printf("%d
    ",ans);
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    《大话数据结构》最小生成树——Prim算法
    《大话数据结构》图的BFS和DFS
    寒假集训日志(三)——数论
    寒假集训日志(二)——最小生成树,拓扑排序,欧拉回路,连通路
    set
    寒假集训日志(一)——图,最短路问题
    经典的图论算法,C++描述
    动态数组
    stack and queue
    最长递增子序列,最长公共子串,最长公共子序列问题,最长公共增长子序列问题
  • 原文地址:https://www.cnblogs.com/klaycf/p/9669407.html
Copyright © 2020-2023  润新知