君と彼女の恋

题目大意及模型转换:

找出有多少个集合满足以下要求:
1、所有数模M两两不同
2、所有数之和为N
N<=10^18,M<=100。结果很大,要求模一个大质数。
集合包含同样的数,而顺序不同视为不同集合。

小思路:

为了满足约束1,可以先选出一些余数(0~M-1),然后不断给其中的余数加M(这样显然这个数模M不会改变),直至达到N。也就是说,题目转换为选一些余数,使余数之和与N对模M同余,并统计将这些余数,每次不断加M,直至达到N的方案数。

DP:

显然可以想到,余数之和最大为M^2(实际为M*(M-1)/2,这里为了叙述方便)。那么我们发现,还要记录个数(因为如果已知余数和为i,还要知道用多少个构成了i,才能统计方案数)。那么个数最大为M。可以设f[i,j]表示选了j个余数使其和为i的方案数。那么显然可以写出转移式f[i,j]=∑f[i-k,j-1]。枚举k需要O(M),枚举状态需要O(M^3)。可以得知此DP是O(M^4)的。

统计答案:

现在,我们假设Q=N mod M,P=N div M。我们可以枚举一个j,要求余数和为Q+j*M,那么可以得知这样我们还需要反复做以下操作P-j次:不断给其中一个余数加M。注意了,假设用i个余数组成,那么方案并不是i^(P-j)的,因为会有重复。这时我们考虑这样一个组合数问题。

隔板放球:

考虑这样一个问题,在N个盒子里放入M个球的方案数。我们可以把N个盒子看作N+1个隔板,那么除去两边没有用的隔板一共有N-1个隔板,放入M个球后,如果把球与隔板统称为“东西”,那么一共有N+M-1个“东西”,其中有N-1个“东西”是隔板。所以,我们可以得出方案数为CN1N+M1

求解组合数:

注意到N+M-1会变得很大,我们需要快速求解组合数。以下有两种方法

方法一

CXY=Y!X!(YX)!=(Y1)!(X1)!(YX)!Y/X=CX1Y1Y/X
因此我们可以不断把弄下去直至变为C0YX,然后再推回来,复杂度为O(X),可以得出X<=M。

方法二

CXY=Y!X!(YX)!=Yi=YX+1iX!
那么就可以用O(X)的方法算出。

注意:

由于是排列,所以还要乘上i的阶乘(i表示为选择了i个余数)。计算组合数用到了除法,我们应该改为乘以它的逆元。因为模的是大质数,所以满足费马小定理前提,那么a*b同余a/b’。其中b*b’=1(mod p),且b’=b^(p-2) mod p。
由于每个余数只能选一次,是01背包问题,所以枚举时次数与和都得倒序,而且转移用到的k放在第一层。

### Yukicoder 473 '和と積和' 题意解析解法 Yukicoder 473 '和と積和' 是一道涉及数学计算的题目,主要考察对数列、和积的计算能力。以下是题意解析解法。 #### 题目描述 给定一个整数 \( n \),你需要计算所有长度为 \( n \) 的数列 \( a_1, a_2, \ldots, a_n \) 的“和积的和”的总值。其中,每个数列中的元素 \( a_i \) 满足 \( 1 \leq a_i \leq m \),且 \( m \) 是一个给定的整数。最终结果需要对 \( 10^9 + 7 \) 取模输出。 公式化表示为: \[ \text{Result} = \sum_{a_1=1}^{m} \sum_{a_2=1}^{m} \cdots \sum_{a_n=1}^{m} \left( \sum_{i=1}^{n} a_i + \prod_{i=1}^{n} a_i \right) \mod (10^9 + 7) \] #### 解法思路 为了高效解决该问题,我们需要避免直接枚举所有可能的数列组合,因为当 \( n \) 和 \( m \) 较大时,这种暴力方法会导致时间复杂度过高。以下是优化后的解法步骤: 1. **分解公式** 将目标公式分解为两部分: \[ \text{Result} = \text{Sum of all sums} + \text{Sum of all products} \] - 第一部分是所有数列中元素和的总和。 - 第二部分是所有数列中元素积的总和。 2. **计算所有数列中元素和的总和** 对于每个位置 \( i \),其贡献可以单独计算。假设某个位置 \( i \) 上的值为 \( a_i \),那么它在所有数列中出现的次数为 \( m^{n-1} \)(因为其他 \( n-1 \) 个位置可以自由选择)。因此,所有数列中元素和的总和为: \[ \text{Sum of all sums} = n \cdot m^{n-1} \cdot \frac{m(m+1)}{2} \mod (10^9 + 7) \] 这里的 \( \frac{m(m+1)}{2} \) 是从 1 到 \( m \) 的整数和。 3. **计算所有数列中元素积的总和** 假设某一个数列的积为 \( P = a_1 \cdot a_2 \cdot \ldots \cdot a_n \),则可以通过递推的方式计算所有可能的积的总和。具体地,定义 \( f(k) \) 表示长度为 \( k \) 的数列的所有积的总和,则有递推关系: \[ f(k) = f(k-1) \cdot \text{Sum of all possible values} \mod (10^9 + 7) \] 其中,\(\text{Sum of all possible values}\) 是从 1 到 \( m \) 的所有可能值的和,即 \( \frac{m(m+1)}{2} \)。初始条件为 \( f(0) = 1 \)。 4. **合并结果** 最终结果为: \[ \text{Result} = \text{Sum of all sums} + f(n) \mod (10^9 + 7) \] #### 示例代码 以下是基于上述思路的 Python 实现代码: ```python MOD = 10**9 + 7 def solve(n, m): # 计算从 1 到 m 的整数和 sum_of_values = m * (m + 1) // 2 % MOD # 计算 Sum of all sums sum_of_sums = n * pow(m, n-1, MOD) * sum_of_values % MOD # 计算 Sum of all products sum_of_products = 1 for _ in range(n): sum_of_products = sum_of_products * sum_of_values % MOD # 合并结果 result = (sum_of_sums + sum_of_products) % MOD return result # 输入 n 和 m n, m = map(int, input().split()) print(solve(n, m)) ``` #### 注意事项 - 在计算幂次时使用快速幂算法以提高效率,例如 `pow(base, exp, mod)`。 - 所有中间结果都需要对 \( 10^9 + 7 \) 取模,以防止溢出。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值