Codeforces Round #516 Div2 D. Labyrinth

https://codeforces.com/contest/1064/problem/D

比赛时先交了个能 AC 的代码,之后感觉 vector 会超时,然后重交了一份,开了个很大的静态数组,system test 时直接爆了 ML。

不过赛后说什么也没用了对吧。。。

题意

有一个迷宫,你可以上下左右走,但是要求左走的次数不超过 \(x\),右走的次数不超过 \(y\),问有多少个点能从起点到达。

题解

比赛时瞪了一会儿样例随便 yy 了个贪心,但是不会证。。。

一个点能被到达,当且仅当存在一条向左次数不超过 \(x\) 的路径,向右次数不超过 \(y\) 的路径。。。是不是听起来很假啊。。。

直接跑 Dijkstra 貌似比较虚,用基数堆可以硬怼过去。

但是我个傻 x 没注意到边权只有 \(0\) 和 \(1\),直接双端队列跑 BFS 即可。。。

#include <bits/stdc++.h>

using namespace std;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, r, c, bl, br;
  cin >> n >> m >> r >> c >> bl >> br;
  r--;
  c--;
  vector<string> board(n);
  for (int i = 0; i < n; i++) {
    cin >> board[i];
  }
  auto get_id = [&](int x, int y) {
    return x * m + y;
  };
  vector< vector< pair<int, pair<int, int> > > > g(n * m);
  const int dx[] = {-1, 0, 1, 0};
  const int dy[] = {0, 1, 0, -1};
  for (int x = 0; x < n; x++) {
    for (int y = 0; y < m; y++) {
      if (board[x][y] == ‘*‘) {
        continue;
      }
      int me = get_id(x, y);
      for (int k = 0; k < 4; k++) {
        int xk = x + dx[k];
        int yk = y + dy[k];
        if (xk < 0 || xk >= n || yk < 0 || yk >= m || board[xk][yk] == ‘*‘) {
          continue;
        }
        int him = get_id(xk, yk);
        g[me].push_back({him, {k == 3, k == 1}});
      }
    }
  }
  deque<int> q;
  q.push_back(get_id(r, c));
  const int inf = numeric_limits<int>::max();
  vector<int> dist(n * m, inf);
  dist[get_id(r, c)] = 0;
  while (!q.empty()) {
    int v = q.front();
    int d = dist[v];
    q.pop_front();
    for (auto &e : g[v]) {
      int u = e.first;
      int w = e.second.first;
      if (dist[u] <= d + w) {
        continue;
      }
      if (w == 0) {
        q.push_front(u);
        dist[u] = d;
      } else {
        q.push_back(u);
        dist[u] = d + 1;
      }
    }
  }
  vector<char> alive(n * m);
  for (int i = 0; i < n * m; i++) {
    alive[i] = (dist[i] <= bl);
  }
  q.push_back(get_id(r, c));
  fill(dist.begin(), dist.end(), inf);
  dist[get_id(r, c)] = 0;
  while (!q.empty()) {
    int v = q.front();
    int d = dist[v];
    q.pop_front();
    for (auto &e : g[v]) {
      int u = e.first;
      int w = e.second.second;
      if (dist[u] <= d + w) {
        continue;
      }
      if (w == 0) {
        q.push_front(u);
        dist[u] = d;
      } else {
        q.push_back(u);
        dist[u] = d + 1;
      }
    }
  }
  int ans = 0;
  for (int i = 0; i < n * m; i++) {
    if (alive[i] && dist[i] <= br) {
      ans++;
    }
  }
  cout << ans << ‘\n‘;
  return 0;
}

原文地址:https://www.cnblogs.com/hfccccccccccccc/p/9788693.html

时间: 2024-08-02 01:26:42

Codeforces Round #516 Div2 D. Labyrinth的相关文章

codeforces round #257 div2 C、D

本来应该认真做这场的,思路都是正确的. C题,是先该横切完或竖切完,无法满足刀数要求,再考虑横切+竖切(竖切+横切), 因为横切+竖切(或竖切+横切)会对切割的东西产生交叉份数,从而最小的部分不会尽可能的大. 代码如下,虽然比较长.比较乱,但完全可以压缩到几行,因为几乎是4小块重复的代码,自己也懒得压缩 注意一点,比如要判断最小块的时候,比如9行要分成2份,最小的剩下那份不是9取模2,而应该是4 m/(k+1)<=m-m/(k+1)*k          #include<bits/stdc+

codeforces Round #250 (div2)

a题,就不说了吧 b题,直接从大到小排序1-limit的所有数的lowbit,再从大到小贪心组成sum就行了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200000 6 using namespace std; 7 int pos[N],a[N],s[N],f[N],la[N],b[N],i,j,k,ans,n,p

Codeforces Round#320 Div2 解题报告

Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Finding Team Member codeforces 579C A Problem about Polyline codeforces 579D "Or" Game codeforces 579E Weakness and Poorness codeforces 579F LCS Aga

Codeforces Round #254(div2)A

很有趣的题.想到了就非常简单,想不到就麻烦了. 其实就是一种逆向思维:最后结果肯定是这样子: WBWBWBWB... BWBWBWBW... WBWBWBWB... ... 里面有“-”的地方改成“-”就行了. 但是我开始是正着想的,想每个点怎么处理,这还要看它周围点的状态,越想越麻烦... 这题中体现的正难则反的逆向思维很值得学习. #include<iostream> #include<cstdio> #include<cstdlib> #include<cs

Codeforces Round #254(div2)B

就是看无向图有几个连通块,答案就是2n-num. 范围很小,就用矩阵来存图减少代码量. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #inc

Codeforces Round #260(div2)C(递推)

有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了:f[i]=max(f[i-1],f[i-2]+i*num[i]); 这里技巧在于:为了防止麻烦,干脆就所有数的出现次数都记录一下,然后直接从2推到100000(类似于下标排序),就不用排序了,也不用模拟删除操作了.这一技巧貌似简单,但实际上临场想出来也需要点水平. #include<iostrea

Codeforces Round #289 Div2 E

Problem 给一串长度为N的字符串,对于每个字符,若字符为元音,则权值为1,否则为0.一个子串的权值定义为该串所有字符权值之和除以字符个数,一个母串的权值定义为所有子串的权值之和.求母串的权值. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N: [1, 5*10^5] 字符集: 'A'-'Z' 元音: I E A O U Y Solution 考虑每个元音字符对母串的贡献,可以找出规律. More 举"ABCDOEFGHKMN"

Codeforces Round #403 div2 C. Andryusha and Colored Balloons

题目链接:Codeforces Round #403 div2 C. Andryusha and Colored Balloons 题意: 给你一棵n个节点的树,然后让你染色,规定相连的三个 节点不能同色,问需要的最少颜色,并输出其中一种方案. 题解: 因为只有相邻3个节点不同色. 所以直接DFS,每个节点都从1开始. 然后ans[v]!=ans[u]!=ans[fa]就行. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i&

CodeForces Round#229 DIV2 C 递推DP

对这道题目也只好说呵呵了,没注意k的范围最大才10,所以昨晚纠结了很久,没什么好的方法来处理,后来无奈想去翻翻题解,发现人家开头就来了句,因为k的范围比较小 所以.........我只好暂停马上回头看看题目,是的,k比较小所以完全可以先在询问前预处理DP一遍, DP就比较清晰了,dp[i][j]  (i>=0 && i<k,,,,j>=i && j <=n)代表意义呢 以i为开头的  区间[1,j]注意 是 1~j的 所需要的操作数,题目问的是最小操