【蓝桥杯 2024 国 Java A】粉刷匠小蓝

【蓝桥杯 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

感谢观看,如有问题欢迎指出。

更新日志

  1. 2025/09/10 开始书写本篇 CSDN 博客,并完稿发布。
相关推荐
酷讯网络_2408701602 小时前
多语言共享贩卖机投资理财共享售卖机投资理财系统
学习·开源
番薯大佬2 小时前
Python学习-day8 元组tuple
java·python·学习
小吴同学·3 小时前
OPC Client第10讲:实现主界面;获取初始界面传来的所有配置信息config【C++读写Excel:xlnx;ODBC;缓冲区】
c++·wxwidgets
wanzhong23333 小时前
ArcGIS学习-17 实战-密度分析
学习·arcgis
边疆.3 小时前
【C++】继承详解
开发语言·c++·继承
hweiyu003 小时前
C++设计模式,高级开发,算法原理实战,系统设计与实战(视频教程)
c++·算法·设计模式
知识分享小能手3 小时前
React学习教程,从入门到精通,React 组件生命周期详解(适用于 React 16.3+,推荐函数组件 + Hooks)(17)
前端·javascript·vue.js·学习·react.js·前端框架·vue3
大千AI助手3 小时前
粒子群优化(PSO)算法详解:从鸟群行为到强大优化工具
人工智能·算法·优化算法·pso·粒子群优化
十年编程老舅3 小时前
‌C++左值与右值:从基础概念到核心应用‌
linux·c++·右值引用·c++17·c++左值·c++右值·左值引用