1. 题目解析与解题思路
这道题目描述了一个有趣的采花问题,我们需要计算所有可能的花田排列方案中,DLS能够采到的花的总数。关键在于理解题目条件和寻找高效的计算方法。
1.1 题目条件分析
题目给出了几个关键条件:
- 有N个花田,每个花田有a_i朵花
- DLS会从左到右采花
- 如果当前花田的花数是之前某个花田花数的因子,则不会采当前花田的花
- 需要计算所有排列方案中采花总数的和
举个例子,对于输入[2,3,6,3],总共有4! = 24种排列方式。我们需要计算每种排列中DLS实际采花数的总和。
1.2 解题思路转换
直接枚举所有排列显然不现实(N≤1e5),我们需要找到数学规律。可以换个角度思考:
对于每个花田中的花数a_i,计算它在所有排列中被采到的总次数。然后对所有a_i的被采次数×a_i求和即可。
一个花田被采的条件是:在它之前的所有花田中,没有数是它的因子。因此,我们需要计算满足这个条件的排列比例。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数学推导与算法设计
2.1 排列概率计算
对于特定的花数x,设总共有m个花田的花数是x的因子(包括x本身)。那么在一个随机排列中,x被采到的概率是1/m,因为x必须出现在所有它的因子之前。
证明:在排列中,x和它的m-1个因子随机排列,x排在最前面的概率是1/m。
2.2 统计因子数量
我们需要预处理每个数x,统计有多少花田的花数是x的因子。这可以通过以下步骤实现:
- 统计每个数出现的次数cnta[x]
- 对于每个x,枚举它的所有倍数,将cnta[x]加到cntb[y]上,其中y是x的倍数
- cntb[x]就是x的因子总数
2.3 计算贡献
对于每个x,它对答案的贡献是:
x × cnta[x] × (总排列数) × (1/cntb[x])
因为:
- 有cnta[x]个x
- 每个x被采的概率是1/cntb[x]
- 总排列数是N!
所以总贡献是:sum(x × cnta[x] × N! / cntb[x])
3. 代码实现详解
3.1 预处理阶乘
cpp复制f1[0] = 1;
for(int i=1;i<=n;i++)
f1[i] = 1ll*f1[i-1]*i%MOD;
f2[n+1] = 1;
fo
