CF1627E. Not Escaping *

34 篇文章 0 订阅
25 篇文章 0 订阅

Link
dp,离散化, 2200

题意

有一栋 n n n 层高楼,每层有 m m m 个房间,现在需要从 ( 1 , 1 ) → ( n , m ) (1,1) \rightarrow (n, m) (1,1)(n,m),同层间向左or右移动需要消耗 x i x_i xi 点体力(每层对应一个 x i x_i xi ),除此之外有 k k k 个梯子,可以从 ( i , j ) → ( p , q ) (i, j)\rightarrow (p, q) (i,j)(p,q) 并恢复 k i k_i ki 点体力,保证 i < p i < p i<p,问到达终点所需的最少体力,或无法到达。 n , m , k ≤ 1 e 5 n,m,k \leq 1e5 n,m,k1e5

思路

由于 n , m ≤ 1 e 5 n, m \leq 1e5 n,m1e5,所以如果直接做的话会t掉,注意到移动过程中楼层不会减少,所以更新时一定是从低层向高层更新。
接下来的问题是如何更新同一层中的点。由于答案只和梯子连接的最多 2 ∗ k 2*k 2k以及起点终点即最多 2 ∗ k + 2 2*k+2 2k+2个点有关,注意到 k ≤ 1 e 5 k \leq 1e5 k1e5,先把同一层的点离散化,并按y从小到大排序,相邻之间只需要 O ( 1 ) O(1) O(1) 转移,正反各扫一遍取最小值。
再对于该层的楼梯起点,更新楼梯终点的dp值。这一步更新的时候一定要保证该起点可达,否则由于起点到终点是负值,可能导致起点不可达但终点也被更新了

代码

const int maxn = 1e5 + 10;
const int maxm = 2e5 + 10;
const int N = 1e3 + 10;
const int P = 998244353;    //998244353
// const int INF = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double EPS=1e-6;  
vector<pii > row[maxn];
ll dp[maxm];
pii to[maxm];
int x[maxn];
int n, m, k;
void solve() {
    cin >> n >> m >> k;
    for(int i = 1; i <= 2 * k + 2; i++) {
    	dp[i] = INF;
    }
    for(int i = 1; i <= n; i++) {
    	row[i].clear();
    }
    for(int i = 1; i <= n; i++) cin >> x[i];
    int cnt = 0;
    dp[1] = 0;
    row[1].push_back(make_pair(1, ++cnt));
    for(int i = 1; i <= k; i++) {
    	int x, y, x1, y1, h;
    	cin >> x >> y >> x1 >> y1 >> h;
    	row[x].push_back(make_pair(y, ++cnt));
    	row[x1].push_back(make_pair(y1, ++cnt));
    	to[cnt - 1] = make_pair(cnt, h);
    }
    row[n].pb(mp(m, ++cnt));
    for(int i = 1; i <= n; i++) {
    	sort(row[i].begin(), row[i].end());
    	for(int j = 1; j < row[i].size(); j++) {
    		dp[row[i][j].se] = min(dp[row[i][j].se], dp[row[i][j-1].se] + 1ll*x[i]*(row[i][j].fi - row[i][j-1].fi));

    	}
    	for(int j = row[i].size() - 2; j >= 0; j--) {
    		dp[row[i][j].se] = min(dp[row[i][j].se], dp[row[i][j+1].se] + 1ll*x[i]*(row[i][j+1].fi - row[i][j].fi));
    	}
    	for(auto j : row[i]) {
    		if(dp[j.se] != INF && to[j.se].fi)
    		dp[to[j.se].fi] = min(dp[to[j.se].fi], dp[j.se] - 1ll*to[j.se].se);
    	}
    }
    if(dp[cnt] != INF) {
    	cout << dp[cnt] << endl;
    }
    else {
    	// puts("NO ESCAPE");
    	cout << "NO ESCAPE\n";
    }
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值