【蓝桥杯 2024 国 Java A】粉刷匠小蓝
蓝桥杯专栏:2024 国 Java A
算法竞赛:数学,组合数学,排列组合,排列数
题目连接:洛谷【蓝桥杯 2024 国 Java A】粉刷匠小蓝
题目描述:
小蓝是一名勤劳的粉刷匠,今天他收到了一份来自蓝桥学院的委托,需要为学院的 n n n 面墙进行粉刷。这 n n n 面墙从左到右依次排列,编号从 1 1 1 到 n n n。起初,所有墙的颜色均为白色。
学院希望小蓝能将其中一部分墙刷成蓝色,以营造一种冷色调的艺术氛围。为此,学院给小蓝提供了一个长度为 n n n 的数组 { a 1 , a 2 , ⋯ , a n } \{a_1, a_2, \cdots, a_n\} {a1,a2,⋯,an},来指定每面墙的颜色要求。具体地,如果 a i = 0 a_i = 0 ai=0,则第 i i i 面墙保持白色;如果 a i = 1 a_i = 1 ai=1,则小蓝需要将第 i i i 面墙刷成蓝色。
小蓝每次只能刷一面墙,他会将一面墙完整的刷完后再刷另一面墙。为了确保整体墙面的视觉效果,学院还提一个小小的要求:在粉刷过程中,如果要将第 i i i 面墙刷成蓝色,那么它右侧(第 i + 1 i + 1 i+1 面墙 ∼ \sim ∼ 第 n n n 面墙)蓝色的墙的个数必须是偶数(包括 0 0 0 个)。
现在,请你计算小蓝共有多少种刷墙顺序可以满足学院的要求?由于答案可能很大,因此你只需要给出答案对 1 0 9 + 7 10^9 + 7 109+7 取模后的结果即可。
在本题中,不同的刷墙方法只与小蓝刷墙的顺序有关。例如,先刷第 1 1 1 面墙再刷第 2 2 2 面墙,与先刷第 2 2 2 面墙再刷第 1 1 1 面墙,被视为两种不同的方法。
输入格式:输入的第一行包含一个正整数 n n n,表示墙的数量。
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an,相邻整数之间使用一个空格分隔,按编号从 1 1 1 到 n n n 的顺序依次表示每面墙的颜色要求。
输出格式:输出一行包含一个整数,表示满足要求的刷墙顺序数量对 1 0 9 + 7 10^9 + 7 109+7 取模后的结果。
数据范围:
- 对于 20 % 20\% 20% 的评测用例, 1 ≤ n ≤ 13 1 \leq n \leq 13 1≤n≤13, a i = 1 a_i = 1 ai=1。
- 对于所有评测用例, 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105, 0 ≤ a i ≤ 1 0 \leq a_i \leq 1 0≤ai≤1。
题目大意
给出一个只含 0 , 1 0,1 0,1 元素的序列,每个元素对应一面墙的状态,元素 0 0 0 表示对应的那一面墙不被粉刷,元素 1 1 1 表示对应的那一面墙将被粉刷,当每刷一面墙时,要求这面墙右面已经被粉刷了的墙的数量必须为偶数(墙从左往右编号),求满足条件的粉刷顺序一共有多少种,结果对 1 0 9 + 7 10^9+7 109+7 取模。
题目分析
不被粉刷的墙舍弃即可,即可转化成 1 ∼ m 1\sim m 1∼m 的满足条件的排列数问题,其中 m m m 是将被粉刷的墙的数量,要满足的条件为排列中每个数的左侧比它大的数的个数必须为偶数。
题目思路
这是一道排列数问题,排列数的求解常用乘法原理。
有 m m m 面将要粉刷的墙,编号为 1 ∼ m 1\sim m 1∼m,正向枚举 1 ∼ m 1\sim m 1∼m 找出每个数可以摆放位置的数量,再将它们相乘即可。
以 m = 5 m=5 m=5 为例,对于编号为 1 1 1 的墙:
位置编号 | 位置 1 | 位置 2 | 位置 3 | 位置 4 | 位置 5 |
---|---|---|---|---|---|
摆放状态 | 可摆放 | 不可摆放 | 可摆放 | 不可摆放 | 可摆放 |
因为在 1 1 1 左侧且比 1 1 1 大的数必须为偶数个,那么 1 1 1 必须摆放在奇数位置上。
对于编号为 2 2 2 的墙:
由于 1 1 1 号墙已经占用了一个位置,那么现在可用的位置只有 m − 1 = 4 m-1=4 m−1=4 个了, 1 < 2 1<2 1<2,则 1 1 1 号墙的位置对 2 2 2 墙没有直接影响,现在有 4 4 4 个位置,将它们重新编号,编号后 2 2 2 号墙也要摆放在奇数编号的位置,道理同上。
位置编号 | 位置 1 | 位置 2 | 位置 3 | 位置 4 |
---|---|---|---|---|
摆放状态 | 可摆放 | 不可摆放 | 可摆放 | 不可摆放 |
3 , 4 , 5 3,4,5 3,4,5 号墙同理。
那么可以得到对应每一面墙编号可摆放的位置的数量为:
n u m i = ⌈ m − ( i − 1 ) 2 ⌉ num_i=\left \lceil \frac{m-(i-1)}{2} \right \rceil numi=⌈2m−(i−1)⌉
其中, m m m 为要粉刷的墙的数量, i i i 为现在粉刷的墙的编号,从 1 ∼ m 1\sim m 1∼m。
那么总方案数即为:
∏ i = 1 m ⌈ m − ( i − 1 ) 2 ⌉ \prod_{i=1}^{m} \left \lceil \frac{m-(i-1)}{2} \right \rceil i=1∏m⌈2m−(i−1)⌉
为了程序更便利地编写,可以将形式转换为:
∏ i = 1 m ⌈ i 2 ⌉ = ∏ i = 1 m ⌊ i + 1 2 ⌋ \prod_{i=1}^{m} \left \lceil \frac{i}{2} \right \rceil=\prod_{i=1}^{m} \left \lfloor \frac{i+1}{2} \right \rfloor i=1∏m⌈2i⌉=i=1∏m⌊2i+1⌋
AC Code
cpp
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;//模数
int main()
{
int n,cnt=0,ans=1;//cnt--将被粉刷的墙的数量,ans--最终方案数
scanf("%d",&n);
while (n--)//后面不用 n,直接 n-- 即可
{
int x;
scanf("%d",&x);
if (x) cnt++;//也可以写成 cnt+=x;
}
for (int i=1;i<=cnt;i++)
ans=(long long)ans*((i+1)/2)%mod;//注意使用 long long 类型计算
printf("%d",ans);
return 0;
}
END
感谢观看,如有问题欢迎指出。
更新日志
- 2025/09/10 开始书写本篇 CSDN 博客,并完稿发布。