首页 > 其他分享 >ABC337 D Cheating Gomoku Narabe 题解

ABC337 D Cheating Gomoku Narabe 题解

时间:2024-01-21 12:44:07浏览次数:29  
标签:ch 窗口 int 题解 -- Cheating ans Gomoku now

Question

ABC337 D Cheating Gomoku Narabe

给出一个 \(H\times W\) 的矩阵,由 ox. 组成,一次操作为把一个 . 变成 o ,问需要最少多少次操作使得横着或竖着有连续的 \(K\) 个 o

Solution

先来考虑只有一行的情况,我们定义一个长度为 \(K\) 的 "窗口",假设需要把这个 "窗口" 里面的所有字母都变成 o,将窗口右移,对于每一种情况取一个最小值就是答案

image.png

那么,我们如何维护每个窗口里面 x 的数量和 . 的数量,当 x 的数量 \(>0\) 时,说明这个窗口不可能满足条件,. 的数量就表示这个窗口达到满足条件需要操作的次数

定义 num_num_x 表示当前窗口 x 的数量和 . 的数量,把窗口往右移动的时候,改变的量只有头和尾两个元素,我们只需要判断两个元素是否为 x. 即可

如果多行的情况,对每一行单独处理,然后翻转行和列再处理一次

当然,这题用双指针和前缀和也能做

Code

#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

char read_ch(){
    char ch=getchar();
    while(ch!='.'&&ch!='o'&&ch!='x') ch=getchar();
    return ch;
}

int main(){
    freopen("D.in","r",stdin);
    freopen("D.out","w",stdout);
    int n = read(), m = read(), k = read();
    vector<vector<int> > a(n+1,vector<int>(m+1));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j] = read_ch();
    int ans = INF;
    
    if(k <= m)
        for(int i=1;i<=n;i++){
            int num_ = 0,num_x = 0;
            for(int j=1;j<=k;j++){
                if(a[i][j]=='.') num_++;
                if(a[i][j]=='x') num_x++;
            }
            if(num_x==0) ans = min(ans,num_);
            for(int j=k+1;j<=m;j++){
                int t_1 = j-k, t_2 = j;
                if(a[i][t_1]=='.') num_--;
                if(a[i][t_1]=='x') num_x--;
                if(a[i][t_2]=='.') num_++;
                if(a[i][t_2]=='x') num_x++;
                if(num_x==0) ans = min(ans,num_);
            }
        }

    if(k <= n)
        for(int j=1;j<=m;j++){
            int num_ = 0,num_x = 0;
            for(int i=1;i<=k;i++){
                if(a[i][j]=='.') num_++;
                if(a[i][j]=='x') num_x++;
            }
            if(num_x==0) ans = min(ans,num_);
            for(int i=k+1;i<=n;i++){
                int t_1 = i-k, t_2 = i;
                if(a[t_1][j]=='.') num_--;
                if(a[t_1][j]=='x') num_x--;
                if(a[t_2][j]=='.') num_++;
                if(a[t_2][j]=='x') num_x++;
                if(num_x==0) ans = min(ans,num_);
            }
        }

    printf("%d\n",ans == INF ? -1 : ans);
    return 0;
}

双指针

#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

char read_ch(){
    char ch=getchar();
    while(ch!='.'&&ch!='o'&&ch!='x') ch=getchar();
    return ch;
}

int main(){
    freopen("D.in","r",stdin);
    freopen("D.out","w",stdout);
    int n = read(), m = read(), k = read();
    vector<vector<int> > a(n+5,vector<int>(m+5));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j] = read_ch();
    int ans = INF;
    
    for(int i=1;i<=n;i++){
        int r = 0;
        int now_ans = 0, now_k = 0;
        for(int j=1;j<=m;j++){
            while(r + 1 <= m && now_k < k) {
                if(a[i][r+1] == '.') now_ans++ , now_k++;
                if(a[i][r+1] == 'o') now_k++;
                r++;
            }
            if(now_k >= k && r-j+1 == k) ans = min(ans, now_ans);
            if(a[i][j] == '.') now_ans-- , now_k--;
            if(a[i][j] == 'o') now_k--;
        }
    }

    for(int j=1;j<=m;j++){
        int r = 0;
        int now_ans = 0, now_k = 0;
        for(int i=1;i<=n;i++){
            while(r + 1 <= n && now_k < k) {
                if(a[r+1][j] == '.') now_ans++ , now_k++;
                if(a[r+1][j] == 'o') now_k++;
                r++;                
            }
            if(now_k >= k && r-i+1==k) ans = min(ans, now_ans);
            if(a[i][j] == '.') now_ans-- , now_k--;
            if(a[i][j] == 'o') now_k--;
        }
    }

    printf("%d\n",ans == INF ? -1 : ans);
    return 0;
}

标签:ch,窗口,int,题解,--,Cheating,ans,Gomoku,now
From: https://www.cnblogs.com/martian148/p/17977724

相关文章

  • CF526F Pudding Monsters 题解
    题目链接:CF或者洛谷析合树真是连续段问题的降智神器先看下题目的一些特殊性,每行每列恰好有一个棋子。考虑特殊性,\(n\timesn\)的棋盘,那么就该判断是否有\(n\)个棋子,容易观察到,也就是相当于每一行并且每一列都有一个棋子。而容易知道,这些棋子所在的行或者列拿出来应当是“......
  • P4148 简单题 题解
    QuestionP4148简单题有一个\(n\timesn\)的棋盘,每个格子内有一个整数,初始时全部为\(0\),现在需要维护两种操作1xy将格子\(x,y\)里的数字加上\(A\)2x1y1x2y2输出\(x_1,y_1,x_2,y_2\)这个矩形内的数字和强制在线Solution因为强制在线,没法用CDQ什么乱搞,这......
  • P4747 [CERC2017] Intrinsic Interval 题解
    题目链接:IntrinsicInterval讲讲析合树如何解决这种问题,其实这题很接近析合树的板题的应用。增量法进行析合树建树时,需要用ST表预处理出\(max\)和\(min\)以便\(O(1)\)查询极差,然后线段树去维护\([l,r]\)上的极差减区间端点做差即\(diff-(r-l)\),当这玩意等于\(0\)时......
  • P8112 [Cnoi2021] 符文破译 题解
    题目传送门思路先看数据范围,我们发现两个字符串的长度最大会达到\(5\times10^7\)。这立刻打消了我用暴力的想法。于是,我选择了用KMP模式匹配,这一个能够在线性时间内判定字符串\(A\)是否是字符串\(B\)的字串,并求出字符串\(A\)在字符串\(B\)中各次出现的位置。如......
  • HDU2966 In case of failure 题解
    QuestionHDU2966Incaseoffailure给出平面上\(n\)个点坐标,求每个点最近的点的欧几里得距离的平方Solution算是一道K-D树的板子题维度\(K=2\)建立\(K-D\)树,在每一层更新当前最小答案\(now\_ans\),如果在然后继续遍历当前维度下距离\(\le\)的区块随机数据时间复......
  • 题解 P6226 [BalticOI 2019 Day1] 潜艇
    【洛谷博客】题解P6226[BalticOI2019Day1]潜艇题意很清楚,忽略。分析看到这种字符串题很容易想到直接广度优先搜索,复杂度\(O(rc4^m)\)。很显然承受不了,所以考虑DP。状态设计设\(f_{i,x,y}\)表示执行完前\(i\)个操作后位置\((x,y)\)能否作为终点。设命令字符......
  • 题解 [ABC321D] Set Menu
    【洛谷博客】题意给定一个长度为\(N\)的正整数数列\(A\),和一个长度为\(M\)的正整数数列\(B\),还有一个正整数\(P\)。你需要求:\[\sum\limits^{N}_{i=1}\sum\limits^{M}_{j=1}\min(A_i+B_j,P)\]分析说实话感觉这题比C还要简单。先考虑单个\(A_i\)能产生的贡献,可以......
  • 题解 [ABC321C] 321-like Searcher
    【洛谷博客】题意给定一个\(k\),你需要找到第\(k\)小的满足下面条件的正整数:对于这个数的每一位,高位大于低位。分析这个数据范围仅有一个\(1\lek\),让人很不好下手。我们不妨先做一个DP,看有多少个满足这样条件的数。设\(f_{i,j}\)表示有\(i\)位,且最高位为\(j\)......
  • 题解 [ABC242D] ABC Transform
    【洛谷博客】很巧妙的一道题。题意给定一个字符串\(S\),只包含字符A,B,C。每过一个时刻,字符会发生变化:A\(\to\)BC,B\(\to\)CA,C\(\to\)AB。设\(0\)时刻为\(S_0=S\)。进行\(Q\)次询问,每次询问时刻\(t\)时,字符串\(S_t\)中第\(k\)个字符。分析为了方便处理,我这里将所......
  • 题解 [ABC144E] Gluttony
    【洛谷博客】题意翻译很清楚,略。分析经过观察最优方案一定是消化代价小的配难消化的菜。所以将\(F\)从小到大排序,\(A\)从大到小排序,当然也可以反着来。因为有\(K\)次修行的机会,难以直接贪心。因为随着时间增加,修行的使用次数会减少,存在单调性。所以考虑使用二分答案转......