Luogu 2254 [NOI2005]瑰丽华尔兹

简单dp,设$f_{i,j,k}$表示第i个时间段,钢琴处在(j,k)位置移动距离的最大值,那么有转移

$f_{i, j, k} = max(f_{i - 1, j, k}) ,  f_{i, j, k} = max(f_{i - 1, a, b})$

其中 

$j - dx_{d_{i}} * len\leq a \leq j -1 $

$k - dy_{d_{i}} * len\leq b \leq k -1 $
$len = ed_{i} - st_{i} + 1 $

其实就是一个滑动窗口,考虑到转移顺序,就是写四遍单调队列~
但是我成功地把方程写错了…… i - 1 写成了 i ,改掉就A了

Code:

#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

const int N = 205;

int n, m, segNum, st[N], ed[N], d[N];
int fx, fy, f[N][N][N], q[N];
char mp[N][N];

inline void read(int &X) {
    X = 0;
    char ch = 0;
    int op = 1;
    for(; ch > '9'|| ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void chkMax(int &x, int y) {
    if(y > x) x = y;
}

inline void print(int p) {
    printf("\n%d\n", p);
    for(int i = 1; i <= n; i++, printf("\n"))
        for(int j = 1; j <= m; j++)
            printf("%10d ", f[p][i][j]);
    system("pause"); 
}

int main() {
    read(n), read(m), read(fx), read(fy), read(segNum);
    for(int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    for(int i = 1; i <= segNum; i++)
        read(st[i]), read(ed[i]), read(d[i]);
    
    memset(f, 0xcf, sizeof(f));
    f[0][fx][fy] = 0;
    for(int i = 1; i <= segNum; i++) {
        for(int j = 1; j <= n; j++)
            for(int k = 1; k <= m; k++)
                if(mp[j][k] != 'x') chkMax(f[i][j][k], f[i - 1][j][k]);
        
//        print(i);
                
        int len = ed[i] - st[i] + 1;
        if(d[i] == 1) {
            for(int k = 1; k <= m; k++) {
                int l = 1, r = 0;
                for(int j = n; j >= 1; j--) {
                    for(; l <= r && q[l] > j + len; l++);
                    if(mp[j][k] == 'x') l = 1, r = 0;
                    else if(l <= r) chkMax(f[i][j][k], f[i - 1][q[l]][k] + (q[l] - j));
                    if(f[i - 1][j][k] >= 0) {
                        for(; l <= r && f[i - 1][q[r]][k] + (q[r] - j) < f[i - 1][j][k]; r--);
                         q[++r] = j;
                    }
                }
            }
        }
        
        if(d[i] == 2) {
            for(int k = 1; k <= m; k++) {
                int l = 1, r = 0;
                for(int j = 1; j <= n; j++) {
                    for(; l <= r && q[l] < j - len; l++);
                    if(mp[j][k] == 'x') l = 1, r = 0;
                    else if(l <= r) chkMax(f[i][j][k], f[i - 1][q[l]][k] + (j - q[l]));
                    if(f[i - 1][j][k] >= 0) {
                        for(; l <= r && f[i - 1][q[r]][k] + (j - q[r]) < f[i - 1][j][k]; r--);
                        q[++r] = j;
                    }
                }
            }
        }
        
        if(d[i] == 3) {
            for(int j = 1; j <= n; j++) {
                int l = 1, r = 0;
                for(int k = m; k >= 1; k--) {
                    for(; l <= r && q[l] > k + len; l++);
                    if(mp[j][k] == 'x') l = 1, r = 0;
                    else if(l <= r) chkMax(f[i][j][k], f[i - 1][j][q[l]] + (q[l] - k));
                    if(f[i - 1][j][k] >= 0) {
                        for(; l <= r && f[i - 1][j][q[r]] + (q[r] - k) < f[i - 1][j][k]; r--);
                        q[++r] = k;
                    }
                }
            }
        }
        
        if(d[i] == 4) {
            for(int j = 1; j <= n; j++) {
                int l = 1, r = 0;
                for(int k = 1; k <= m; k++) {
                    for(; l <= r && q[l] < k - len; l++);
                    if(mp[j][k] == 'x') l = 1, r = 0;
                    else if(l <= r) chkMax(f[i][j][k], f[i - 1][j][q[l]] + (k - q[l]));
                    if(f[i - 1][j][k] >= 0) {
                        for(; l <= r && f[i - 1][j][q[r]] + (k - q[r]) < f[i - 1][j][k]; r--);
                        q[++r] = k;
                    }
                }
            }
        }
        
        
//        print(i);
    } 
    
    int ans = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            chkMax(ans, f[segNum][i][j]);
    printf("%d\n", ans);
    
    return 0;
}

还是要仔细a

posted @ 2018-08-13 10:00  CzxingcHen  阅读(144)  评论(0编辑  收藏  举报