首页 > 其他分享 >CF518F 题解

CF518F 题解

时间:2024-04-25 15:23:48浏览次数:22  
标签:int 题解 toU ++ && ans CF518F toD

观察到一条管道的拐点数量只有 \(3\) 种可能的取值:

  • 没有拐点,即管道呈现一条直线。
  • 有 \(1\) 个拐点。
  • 有 \(2\) 个拐点。

分别对应了下面三种情况:

....#           ....#            .*..#
*****           ****.            .***.
..#..           ..#*.            ..#*.
#...#           #..*#            #..*#
.....           ...*.            ...*.

考虑对这三种情况分别计数,先预处理出来几个辅助数组 ( bool 类型 ) \(U[i][j], D[i][j], L[i][j], R[i][j]\),\(U[i][j]\) 表示从 \((i, j)\) 到 \((1, j)\) 的路上是否无障碍物,即从 \((i, j)\) 一直往上走的路径上是否无障碍物。\(D[i][j], L[i][j], R[i][j]\) 同理,分别表示往下走 \((i, j) \to (n, j)\)、往左走 \((i, j) \to (i, 1)\)、往右走 \((i, j) \to (i, m)\) 的路上是否不存在障碍物。特别地,对于有障碍物的格子 \((i, j)\),有 \(U[i][j] = D[i][j] = L[i][j] = R[i][j] = 0\)。

分类讨论拐点数量:

  • 对于没有拐点的情况,答案是 \(\sum\limits_{i=2}^{n-1}R[i][0]+\sum\limits_{i=2}^{m-1}D[0][i]\)。
  • 对于有 \(1\) 个拐点的情况,考虑枚举拐点的位置,接着枚举管道通往的方向,并根据对应的 \(U, D, L, R\) 数组计算贡献即可。这部分的答案为 \(\sum\limits_{i = 2}^{n - 1}\sum\limits_{j = 2}^{m - 1} (L[i][j] + R[i][j]) \times (D[i][j] + U[i][j])\)。
  • 对于有 \(2\) 个拐点的情况,分成两种子情况:第一种是管道先竖着走再横着走再竖着走;第二种是先横着走再竖着走再横着走。可以发现两种情况类似,下面只讨论第一种情况:
    先枚举横着走的那一行,从左往右扫每一列,记当前行为 \(i\),列为 \(j\)。记录两个值 \(toU, toD\),分别表示 \(2 \sim (j - \textbf{2})\) 中有多少列能向上走,有多少列能向下走,且第 \(i\) 行内第 \(j\) 列与这些列之间没有障碍物。考虑贡献答案,先特殊考虑 \(j - 1\) 列的贡献 ( 因为 \(j\) 列和 \(j - 1\) 列不能同时往上或者同时往下 ),再考虑 \(2 \sim (j - 2)\) 列,显然这部分对答案贡献为 \((U[i][j] + D[i][j]) \times (toU + toD)\)。离开第 \(j\) 列时更新一下 \(toU\) 和 \(toD\) 即可。
    第二种情况类似处理出 \(toL\) 和 \(toR\) 即可。

至此本题解决,复杂度 \(O(nm)\)。下面是代码:

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

signed main(void) {
    ios :: sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int n, m;
    cin >> n >> m;
    vector <vector <char>> a(n, vector <char> (m));
    vector <vector <int>> u(n, vector <int> (m));
    auto d = u, l = u, r = u;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            cin >> a[i][j];
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            u[i][j] = (!i ? 1 : u[i - 1][j]) && (a[i][j] == '.');
            l[i][j] = (!j ? 1 : l[i][j - 1]) && (a[i][j] == '.');
        }
    }
    for (int i = n - 1; i >= 0; --i) {
        for (int j = m - 1; j >= 0; --j) {
            d[i][j] = (i + 1 == n ? 1 : d[i + 1][j]) && (a[i][j] == '.');
            r[i][j] = (j + 1 == m ? 1 : r[i][j + 1]) && (a[i][j] == '.');
        }
    }

    i64 ans = 0;
    for (int i = 1; i + 1 < n; ++i)
        ans += r[i][0];
    for (int j = 1; j + 1 < m; ++j)
        ans += d[0][j];

    for (int i = 1; i + 1 < n; ++i)
        for (int j = 1; j + 1 < m; ++j)
            ans += (l[i][j] + r[i][j]) * (d[i][j] + u[i][j]);

    for (int j = 1; j + 1 < m; ++j) {
        int toL = 0, toR = 0;
        for (int i = 1; i + 1 < n; ++i) {
            if (l[i][j])
                ans += toL + toR + (i > 1 && r[i - 1][j]);
            if (r[i][j])
                ans += toL + toR + (i > 1 && l[i - 1][j]);
            if (i > 1) {
                toL += l[i - 1][j];
                toR += r[i - 1][j];
            }
            if (a[i][j] == '#') {
                toL = 0;
                toR = 0;
            }
        }
    }
    for (int i = 1; i + 1 < n; ++i) {
        int toU = 0, toD = 0;
        for (int j = 1; j + 1 < m; ++j) {
            if (u[i][j])
                ans += toU + toD + (j > 1 && d[i][j - 1]);
            if (d[i][j])
                ans += toU + toD + (j > 1 && u[i][j - 1]);
            if (j > 1) {
                toU += u[i][j - 1];
                toD += d[i][j - 1];
            }
            if (a[i][j] == '#') {
                toU = 0;
                toD = 0;
            }
        }
    }

    cout << ans << '\n';
}

标签:int,题解,toU,++,&&,ans,CF518F,toD
From: https://www.cnblogs.com/CTHOOH/p/18157297

相关文章

  • 2023CPCC河南省赛题解+总结
    2023CPCC河南省赛题解+总结比赛链接:https://codeforces.com/gym/104354答题情况:答题情况开题顺序是:A-F-H-K-E-B-G题面链接:https://codeforces.com/gym/104354/attachments/download/20061/statements_2.pdfProblemA.小水獭游河南签到题,队友写的题意:  给你一个字符......
  • git命令下,mac环境下载依赖相关报错问题解决方案
    1.安装fundry框架curl-Lhttps://foundry.paradigm.xyz|bash2.写入环境变量source/Users/xx/.bashrc3.foundryup问题1报错:致命错误:无法访问'https://github.com/foundry-rs/forge-std解决方案:设置hosts文件:添加指定url的ip地址:140.82.112.4github.com185.1......
  • 【题解】A566.三点共线
    题目大意,给定在平面直角坐标系中的多个点,判断有多少个三元组\((A,B,C)\)满足共线性质。题目链接:A566.三点共线。大题思路就是暴力所有的三元组,判断三个元素的斜率是否相同即可。其实还有其他方法可以做,我个人感觉用斜率法最简单。有几点需要注意:在计算斜率的时候,如果多......
  • ABC350 E - Toward 0 题解
    AtCoderBeginnerContest350E-Toward0原题地址题意给定四个数NAXY,你可以对N进行以下两种操作。花费X的代价将N变成\(\lfloor\cfrac{N}{A}\rfloor\)花费Y的代价掷一颗骰子,设掷出结果是i,将N变成\(\lfloor\cfrac{N}{i}\rfloor\)你需要执行若干次......
  • 前端调用DRI后端API出现跨域资源共享(CORS)问题解决办法
    目录1.引言2.跨源资源共享和实现方法3.在Django项目中配置django-cors-headers库Reference1.引言在进行后端API开发时,有时会遇到“跨域资源共享(CORS)请求...被阻止“的错误,如图1所示。本文讲解如何在使用DRF(DjangoRESTFramework)的后端API开发项目中解决这个问题。Ac......
  • Codeforces Round 940 (Div. 2) and CodeCraft-23 题解
    CodeforcesRound940(Div.2)andCodeCraft-23题解题目链接A.Stickogon贪心#include<bits/stdc++.h>usingnamespacestd;#definefffirst#definesssecond#definepbpush_back#defineall(u)u.begin(),u.end()#defineendl'\n'#definedebu......
  • [HNOI2005] 星际贸易 题解
    [HNOI2005]星际贸易将问题分为两次dp。题面有:“只有一种获得最大贸易额的方法”所以直接说明了贸易额与那些费用无关。有考虑到无论干啥都要维护,第二次\(dp\)直接以暗物质为核心即可对于这里\(R\)与\(n*2\)取\(min\)的一些细节理解。我们设计状态,因为观察到了暗......
  • 洛谷 P8989 [北大集训 2021] 随机游走 题解
    前言又是随机游走?题目分析看到加边,可能性太多了。但是为了让步数最大化,我们可以贪心地想,肯定要往前面连,而且越前面要走的期望步数肯定越大。并且,我们不会浪费边在终点上。于是,题目转变成了\(1\simn-1\)连向起点\(1\)连若干条边,使得随机游走到终点的期望步数最大。那要......
  • [题解]P5431 【模板】模意义下的乘法逆元 2
    可恶,卡常好难受。P5431【模板】模意义下的乘法逆元2将分数通分,第\(i\)个分数是\(\frac{k^i*fac\diva[i]}{fac}\),\(fac\)表示所有元素的积。我们可以用\(lr,rl\)记录\(a\)的前缀后缀积,第\(i\)个分数就是\(\frac{k^i*lr[i-1]*rl[i+1]}{lr[n]}\)。这样分母都是\(lr[n]\),分子就......
  • qoj3082 Ascending Matrix 题解
    题目链接点击打开链接题目解法不考虑第\(a_{r,c}=v\)的限制怎么求?我们把条件形式化一下,发现\(k\)个区域的颜色可以表示成轮廓线的形式,即第\(i-1\)条到第\(i\)条轮廓线之间的格点颜色为\(i\)问题变成找到\(k-1\)条互不穿过的路径,起点为\((1,m)\),终点为\((n,1)\)......