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