zoukankan      html  css  js  c++  java
  • [NOI2005]瑰丽华尔兹

    嘟嘟嘟


    这题大家应该都做过,就是暴力dp+单调队列优化。


    dp方程其实很好想,最初是这样的:dp[t][i][j]表示时刻(t)后,走到((i, j))格子的最远路程,于是就有:

    [dp[t][i][j] = max{ dp[t - 1][px][py] } + 1 ]

    但这是(O(Tn ^ 2))的,不仅会TLE,还能MLE。


    接着看题,发现给得(K)没用上。想一下发现(K)的特点是同一时间区间的移动方向是一样的,于是我们把第一维改成第(k)个时间区间,转移方程就变成了:

    [dp[k][i][j] = max_{h = 1} ^ {len}{ dp[k - 1][i - dx[d]][j - dy[d]] + dis(i, j, i - dx[d], j - dy[d])} ]

    (len)表示区间长度。
    方程可能丑了点,但意思就是枚举这个点能在这个时间段内从哪儿转移过来,然后就是对应的dp值加上这两点之间的距离。
    注意如果有的格子不能走,就不能从这里转移。
    复杂度(O(kn ^ 3))


    于是就有单调队列优化啦。
    对于一个点,这一步能转移到他的实际上就是x或y方向上连续的一段dp值,于是我们把这些dp值放进单调队列里就行了。
    这样优化到(O(kn ^ 2)),就过了。
    需要注意的是,我们要用k - 1时刻更新k时刻的答案,因此先把dp[x][y]放入队列,再用队首更新dp值。这样就保证了放进去的dp值一定是上一个时刻的。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 205;
    inline ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), last = ' ';
    	while(!isdigit(ch)) last = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(last == '-') ans = -ans;
    	return ans;
    }
    inline void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, m, sx, sy, K;
    char a[maxn][maxn];
    struct Node
    {
    	int L, R, dir;
    }t[maxn];
    int dp[maxn][maxn];
    
    struct Que
    {
    	int val, x, y;
    }q[maxn];
    int l = 1, r = 0;
    const int dx[] = {0, -1, 1, 0, 0}, dy[] = {0, 0, 0, -1, 1};
    In bool check(int x, int y) {return x && x <= n && y && y <= m;}
    In int dis(int xa, int ya, int xb, int yb) {return abs(xa - xb) + abs(ya - yb);}
    In void solve(int x, int y, int d, int len)
    {
    	l = 1; r = 0;
    	while(check(x, y))
    	{
    		if(a[x][y] == 'x') l = 1, r = 0;
    		else
    		{
    			while(l <= r && q[r].val + dis(x, y, q[r].x, q[r].y) < dp[x][y]) --r;
    			q[++r] = (Que){dp[x][y], x, y};
    			while(l <= r && dis(x, y, q[l].x, q[l].y) > len) ++l;
    			dp[x][y] = q[l].val + dis(x, y, q[l].x, q[l].y);
    		}
    		x += dx[d]; y += dy[d];
    	}
    }
    
    int main()
    {
    	n = read(); m = read(); sx = read(), sy = read(), K = read();
    	for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1);
    	for(int i = 1; i <= K; ++i) t[i].L = read(), t[i].R = read(), t[i].dir = read();
    	Mem(dp, -0x3f); dp[sx][sy] = 0;
    	for(int i = 1; i <= K; ++i)
    	{
    		if(t[i].dir == 1) for(int j = 1; j <= m; ++j) solve(n, j, t[i].dir, t[i].R - t[i].L + 1);
    		if(t[i].dir == 2) for(int j = 1; j <= m; ++j) solve(1, j, t[i].dir, t[i].R - t[i].L + 1);
    		if(t[i].dir == 3) for(int j = 1; j <= n; ++j) solve(j, m, t[i].dir, t[i].R - t[i].L + 1);
    		if(t[i].dir == 4) for(int j = 1; j <= n; ++j) solve(j, 1, t[i].dir, t[i].R - t[i].L + 1);
    	}
    	int ans = 0;
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j) ans = max(ans, dp[i][j]);
    	write(ans), enter;
    }
    
  • 相关阅读:
    android调试推荐使用BlueStacks模拟器调试Android应用
    目录文件Oracle11g彻底删除
    进程间通信学习APUE学习进程间通信(4)
    android选择Windows 8 下配置Cocos2dx + Android + Eclipse 的开发环境
    windbg API 跟踪
    symchk 获取符号文件(PDB)
    acs for PEAPMSCHAPV2
    peapMSCHAPV2
    vs2005 "Key not valid for use in specified state"
    NetUserGetInfo NetUserAdd
  • 原文地址:https://www.cnblogs.com/mrclr/p/10309560.html
Copyright © 2011-2022 走看看