首页 > 其他分享 >[NOIP2022] 种花

[NOIP2022] 种花

时间:2024-01-24 11:46:22浏览次数:30  
标签:10 texttt leq lst 种花 NOIP2022 maxn

题目描述

小 C 决定在他的花园里种出 \(\texttt{CCF}\) 字样的图案,因此他想知道 \(\texttt C\) 和 \(\texttt F\) 两个字母各自有多少种种花的方案;不幸的是,花园中有一些土坑,这些位置无法种花,因此他希望你能帮助他解决这个问题。

花园可以看作有 \(n\times m\) 个位置的网格图,从上到下分别为第 \(1\) 到第 \(n\) 行,从左到右分别为第 \(1\) 列到第 \(m\) 列,其中每个位置有可能是土坑,也有可能不是,可以用 \(a_{i,j} = 1\) 表示第 \(i\) 行第 \(j\) 列这个位置有土坑,否则用 \(a_{i,j} = 0\) 表示这个位置没土坑。

一种种花方案被称为 \(\texttt{C-}\) 的,如果存在 \(x_1, x_2 \in [1, n]\),以及 \(y_0, y_1, y_2 \in [1, m]\),满足 \(x_1 + 1 < x_2\),并且 \(y_0 < y_1, y_2 \leq m\),使得第 \(x_1\) 的第 \(y_0\) 到第 \(y_1\) 、第 \(x_2\) 的第 \(y_0\) 到第 \(y_2\) 以及第 \(y_0\) 的第 \(x_1\) 到第 \(x_2\) 不为土坑,且只在上述这些位置上种花。

一种种花方案被称为 \(\texttt{F-}\) 的,如果存在 \(x_1, x_2, x_3 \in [1, n]\),以及 \(y_0, y_1, y_2 \in [1, m]\),满足 \(x_1 + 1 < x_2 < x_3\),并且 \(y_0 < y_1, y_2 \leq m\),使得第 \(x_1\) 的第 \(y_0\) 到第 \(y_1\) 、第 \(x_2\) 的第 \(y_0\) 到第 \(y_2\) 以及第 \(y_0\) 的第 \(x_1\) 到第 \(x_3\) 不为土坑,且只在上述这些位置上种花。

样例一解释中给出了 \(\texttt{C-}\) 形和 \(\texttt{F-}\) 形种花方案的图案示例。

现在小 C 想知道,给定 \(n, m\) 以及表示每个位置是否为土坑的值 \(\{a_{i,j}\}\),\(\texttt{C-}\) 形和 \(\texttt{F-}\) 形种花方案分别有多少种可能?由于答案可能非常之大,你只需要输出其对 \(998244353\) 取模的结果即可,具体输出结果请看输出格式部分。

输入格式

第一行包含两个整数 \(T, id\),分别表示数据组数和测试点编号。如果数据为样例则保证 \(id = 0\)。

接下来一共 \(T\) 组数据,在每组数据中:

第一行包含四个整数 \(n, m, c, f\),其中 \(n, m\) 分别表示花园的行数、列数,对于 \(c, f\) 的含义见输出格式部分。

接下来 \(n\) 行,每行包含一个长度为 \(m\) 且仅包含 \(0\) 和 \(1\) 的字符串,其中第 \(i\) 个串的第 \(j\) 个字符表示 \(a_{i,j}\),即花园里的第 \(i\) 行第 \(j\) 列是不是一个土坑。

输出格式

设花园中 \(\texttt{C-}\) 形和 \(\texttt{F-}\) 形的种花方案分别有 \(V_C\) 和 \(V_F\) 种,则你需要对每一组数据输出一行用一个空格隔开的两个非负整数,分别表示 \((c \times V_C) \bmod 998244353\),\((f \times V_F ) \bmod 998244353\) ,其中 \(a \bmod P\) 表示 \(a\) 对 \(P\) 取模后的结果。

样例 #1

样例输入 #1

1 0
4 3 1 1
001
010
000
000

样例输出 #1

4 2

提示

【样例 1 解释】

四个 \(\texttt{C-}\) 形种花方案为:

**1 **1 **1 **1
*10 *10 *10 *10
**0 *** *00 *00
000 000 **0 ***

其中 \(\texttt*\) 表示在这个位置种花。注意 \(\texttt C\) 的两横可以不一样长。

类似的,两个 \(\texttt{F-}\) 形种花方案为:

**1 **1
*10 *10
**0 ***
*00 *00

【样例 2】

见附件下的 \(\texttt{plant/plant2.in}\) 与 \(\texttt{plant/plant2.ans}\)。

【样例 3】

见附件下的 \(\texttt{plant/plant3.in}\) 与 \(\texttt{plant/plant3.ans}\)。

【数据范围】

对于所有数据,保证:\(1 \leq T \leq 5\),\(1 \leq n, m \leq 10^3\),\(0 \leq c, f \leq 1\),\(a_{i,j} \in \{0, 1\}\)。

测试点编号 \(n\) \(m\) \(c=\) \(f=\) 特殊性质 测试点分值
\(1\) \(\leq 1000\) \(\leq 1000\) \(0\) \(0\) \(1\)
\(2\) \(=3\) \(=2\) \(1\) \(1\) \(2\)
\(3\) \(=4\) \(=2\) \(1\) \(1\) \(3\)
\(4\) \(\leq 1000\) \(=2\) \(1\) \(1\) \(4\)
\(5\) \(\leq 1000\) \(\leq 1000\) \(1\) \(1\) A \(4\)
\(6\) \(\leq 1000\) \(\leq 1000\) \(1\) \(1\) B \(6\)
\(7\) \(\leq 10\) \(\leq 10\) \(1\) \(1\) \(10\)
\(8\) \(\leq 20\) \(\leq 20\) \(1\) \(1\) \(6\)
\(9\) \(\leq 30\) \(\leq 30\) \(1\) \(1\) \(6\)
\(10\) \(\leq 50\) \(\leq 50\) \(1\) \(1\) \(8\)
\(11\) \(\leq 100\) \(\leq 100\) \(1\) \(1\) \(10\)
\(12\) \(\leq 200\) \(\leq 200\) \(1\) \(1\) \(6\)
\(13\) \(\leq 300\) \(\leq 300\) \(1\) \(1\) \(6\)
\(14\) \(\leq 500\) \(\leq 500\) \(1\) \(1\) \(8\)
\(15\) \(\leq 1000\) \(\leq 1000\) \(1\) \(0\) \(6\)
\(16\) \(\leq 1000\) \(\leq 1000\) \(1\) \(1\) \(14\)

特殊性质 A:\(\forall 1 \leq i \leq n, 1 \leq j \leq \left\lfloor \frac{m}{3} \right\rfloor\),\(a_{i, 3 j} = 1\);

特殊性质 B:\(\forall 1 \leq i \leq \left\lfloor \frac{n}{4} \right\rfloor, 1 \leq j \leq m\),\(a_{4 i, j} = 1\);

题解

这个题是独立做出来的绿题,非常开心
我们来看C的方案,观察样例就知道,对于C的两个顶点,我们需要知道每个顶点右面有几个零,如果知道这点,我们只需要使用乘法原理即可
对于(i,j)这个格子,我们怎么统计他右面有几个零?
刚开始我的方法是暴力维护,暴力维护的时间复杂度太高,我一直T的原因就在这里,后面我进行了修改,倒序枚举,从第m列开始,如果这个格子的数字是0,那么xh[i][j]=xh[i][j+1]+1,否则xh[i][j]=0,当然,我们也需要统计向上有多少个?方法是同样的。

那么我们怎么找C的方案数?我们发现在竖的方向上,至少存在3个连续的0,同时他们右面有多个0,我们是可以有C方案的,可以暴力统计,但是我发现,这个可以递推,用lst[i][j]记录在连续的0里面,目前匹配的数量是多少?如果当然(i,j)连续0的数量符合条件,那么前lst[i-2][j]是符合条件的,也就是说,和(i-2,j)匹配的,一定和他匹配,同时需要加上(i-2,j) 的向右数量,否则,匹配数量为0,同时更新lst[i][j],如何更新lst[i][j]呢?lst[i][j]默认等于lst[i-1][j],如果他自己也能匹配,加上自己向右的数量即可

经过上述过程,记录到pp[i][j]表示前面有多少个匹配数量,直接和0的数量相乘即可,那么C的问题就解决了

C的问题解决了之后,F的问题也就好解决了,因为F正好是C加上1个0,这个想法也是我偶然想到的,不得不说,这题出的实在是妙,我们记录C方案的前缀和即可

反思

对于我来说,最难的部分是对于(i,j)找匹配的问题,之前我一直认为(i,j)的匹配就是(i-1,j)的匹配加上(i-2,j)的向右个数,

代码实现

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int n,m,c,ff,id,t;
char s[maxn][maxn];
int xh[maxn][maxn],f[maxn][maxn],xs[maxn][maxn],pp[maxn][maxn],lst[maxn][maxn],sum[maxn][maxn];
long long ansc,ansf;
int main(){
    //freopen("plant4.in","r",stdin);
    scanf("%d%d",&t,&id);
    for(int ss=1;ss<=t;ss++){
        scanf("%d%d%d%d",&n,&m,&c,&ff);
        memset(xh,0,sizeof xh);
        memset(xs,0,sizeof xs);
        memset(f,0,sizeof f);
        memset(lst,0,sizeof lst);
        memset(pp,0,sizeof pp);
        memset(sum,0,sizeof sum);
        ansc=ansf=0;
        for(int i=1;i<=n;i++){
            scanf("%s",s[i]+1);
            if(s[i][m]=='0') xh[i][m]=1;
            else xh[i][m]=0;
            for(int j=m-1;j>=1;j--)
                if(s[i][j]=='0'){
                    xh[i][j]=xh[i][j+1]+1;
                    xs[i][j]=xs[i-1][j]+1;
                }
                else{
                    xh[i][j]=0;
                    xs[i][j]=0;
                }
        }
//        for(int i=1;i<=n;i++){
//            for(int j=1;j<=m;j++)
//                cout<<xs[i][j]<<" ";
//            cout<<endl;
//        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(s[i][j]=='0'){
                    if(xs[i][j]>=3){
                        if(xh[i][j]>=2) pp[i][j]=lst[i-2][j];
                        else pp[i][j]=0;
                    }
                    if(xh[i][j]>=2) lst[i][j]=lst[i-1][j]+xh[i][j]-1;
                    else lst[i][j]=lst[i-1][j];
                }else{
                    lst[i][j]=0;
                }
                
            }
        }
        for(int i=3;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(s[i][j]=='0'&&xh[i][j]>=2&&xs[i][j]>=3){
                    f[i][j]=(xh[i][j]-1)*pp[i][j]%998244353;
                }
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(s[i][j]=='0') {
                    ansf=(ansf+sum[i-1][j])%998244353;
                    sum[i][j]=(sum[i-1][j]+f[i][j])%998244353;
                    
                }
                else sum[i][j]=0;
            }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                ansc=(ansc+f[i][j])%998244353;
        
        ansc=ansc*c%998244353;
        ansf=ansf*ff%998244353;
        printf("%lld %lld\n",ansc,ansf);
    }
}
/**
1 7
10 10 1 1
0000000000
0000000100
0000100000
0000000000
0000000000
0000000000
0000000001
0000000000
0010000001
0000000000
 */

标签:10,texttt,leq,lst,种花,NOIP2022,maxn
From: https://www.cnblogs.com/sdfzls/p/17984212

相关文章

  • CSP2022 & NOIP2022
    before\(\text{inf}\)days据说今年GD参赛的人数特别多,很慌。8.01按照往年的惯例,又是一年集训时。去年没学好,只好重头开始。今年这一届的队友tql。算是基本上把深进给复习了一遍吧。8.22集训终于结束了。烦人的初赛又来了。CSP模拟套题接连不断。平均分\(70\)左......
  • 吴师兄学算法day08 贪心 605. 种花问题
    题目:605.种花问题易错点:没想出来,借鉴了灵山的代码的思路,强行种花。我喜欢这个思路。感觉有点像设置哨兵那样的。 我的代码:classSolution:defcanPlaceFlowers(self,flowerbed:List[int],n:int)->bool:#修改数组,每次都种花,#凑够3个0......
  • NOIP2022 题解
    去年今时,我得了100+0+0+8分,太抽象了QwQ所以为什么今天才写这个东西?因为今天才做完了T2……[NOIP2022]种花简单前缀和优化DP,不谈。[NOIP2022]喵了个喵非常高级的构造题。看到\(k=2n-1/2\),我们可能会想到每一个栈内放两个即可,留一个辅助栈,即可完美过掉\(k......
  • [NOIP2022] 比赛 - 总结
    [NOIP2022]比赛0.问题转化首先需要转化为区间历史和问题。具体上来讲,就是将询问离线后,扫描线维护对于\(r\)来说,每一个\(l\)的\(\sum_{i=l}^{r}(\max_{j=l}^{i}a_j\\cdot\\max_{j=l}^{i}b_j)\)那么答案就是区间和。1.构造信息与标记接下来就是如何维护区间历史和。......
  • [NOIP2022] 喵了个喵
    补一下往年的构造题。。。\(k\)大概是\(n\)的两倍往下,这启示我们每个栈最多只放两个元素。首先考虑\(k=2n-2\)的分,容易得到一个策略:留一个空栈不放,每个栈最多放两个。如果当前卡牌存在一个栈顶/栈底和它一样,那当前牌总是可以消掉的。否则当前栈中的卡牌一定两两不同,那一定......
  • P8868 [NOIP2022] 比赛
    传送门我们容易想到预处理区间\([l,r]\)中的\(m_a\timesm_b\)。这样算出来的是一个二维的矩阵,每次的答案就是红色部分:但是这样的问题是二维的,无论如何都不是正解。考虑把列这一维压掉,也就是令\(w'_i\leftarroww_{i,i}+w_{i,i+1}+...+w_{i,r}\)。这样询问的......
  • 题解:「NOIP2022 提高组」种花
    题解:「NOIP2022提高组」种花题目大意:给定一个\(n\timesm\)的01矩阵,0表示可以种花,1表示土坑(无法种花),现在要在图上种出一个C型或F型(C,F横着的两条线的长度都可以不同,但一定是面向右边的),现在问你种C和F分别有多少种方案(除了这个形状外不能在任何地方种花),多组数据,\(T\leq5\)。......
  • P8865 [NOIP2022] 种花 题解
    前言去年多测不清空导致即便CCF放过了我的\(O(n^2m)\)的代码但依然挂成了\(0pts\)。当时看清空数组后能过CCF数据就没再管。时隔\(1\)年,重做这道题写了\(O(nm)\)的正解,终于完成了当年的心愿。\(O(n^2m)\)思路想到计算方案的话可以维护两个数组\(c1_{i,j}\)表......
  • 代码随想训练营的第十五天(Python)| 二叉树的前、中、后续遍历(各种花式遍历哈哈)
    前序遍历统一写法用None来区分遍历查找的节点和处理节点1、递归法classSolution:defpreorderTraversal(self,root:Optional[TreeNode])->List[int]:res=[]self.preorder(root,res)returnresdefpreorder(self,root,res):......
  • P8868 [NOIP2022] 比赛
    主要写一写标记的推导。理论大概在关于线段树上的一些进阶操作回忆一下普通历史和。是对两个合并队列做前缀和,然后利用往后插的贡献来计算。\(ht'+add*upd\toht\)\(s*upd+ht'*len\tohs\)下文:\(x\toadda,y\toaddb\)不带历史和的点积:\((a+x)(b+y)......