通过快速幂求出常数项 g(x) = x^x mod 1000,再利用隔板法将求正整数解组数转化为组合数 C(g(x)-1, k-1) 的高精度计算。
OJ: roj
题目 ID: 1653
难度:普及+/提高-
标签:数学组合数学隔板法快速幂高精度
创建: 2026-10-01 00:07
更新: 2026-10-07 13:50
形式化题目
给定正整数
求满足下列条件的不定方程的正整数解
题目保证
正解
思路
本题分为两个独立的计算步骤:
-
计算常数项
: 目标值为 。 虽然 数值较大,但由于只对模数 取模,可以使用整数快速幂在 时间内求出 。 因为 是较小的模数,计算出的 满足 。题面保证 ,因此 。 -
隔板法求不定方程正整数解的个数: 问题转化为将正整数
拆分成 个正整数之和的方案数: 这等价于将个相同的小球排成一列,在它们形成的 个间隔中放置 块隔板,将小球分成非空的 段。 因此,满足条件的正整数解组数即为组合数: -
数值范围与精度: 数据范围中
, 。 组合数 的最大值可能达到几百位数字,远超 位整型范围,需要高精度计算。 在 Python 中,内置整型天然支持任意精度大整数,且标准库 math.comb(n, k)提供了高效的组合数实现。
图示解析
以
text
小球序列: ( 1 ) | ( 2 ) ( 3 ) ( 4 ) | ( 5 ) ( 6 )
间隔编号: 1 2 3 4 5
所选间隔: [选 1] [选 4]
对应解组: a1 = 1 a2 = 3 a3 = 2从
代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 00:07
# update_at: 2026-10-01 00:07
import math
import sys
MOD = 1000 # 方程右端 g(x) 的取模常数
def count_positive_solutions(variables: int, total: int) -> int:
"""隔板法求 total 分成 variables 个正整数之和的解组数,即 C(total - 1, variables - 1)。"""
return math.comb(total - 1, variables - 1)
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
k, x = next(data), next(data)
# 题目给定 g(x) = x^x mod 1000
target_sum = pow(x, x, MOD)
ans = count_positive_solutions(k, target_sum)
print(ans)
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 00:42
* update_at: 2026-10-06 00:42
*/
#include <cstdio>
typedef long long ll;
const int MOD_G = 1000; // g(x) = x^x 对 1000 取模
const int BASE = 1000000000; // 高精度每段保存 9 位十进制数
const int MAXD = 64; // C(998, 99) 约 139 位十进制,64 段足够
ll big[MAXD]; // 高精度数,从低位到高位每段压 9 位,big[0] 为最低段
ll big_len; // 当前占用的段数
// 计算 (base^exp) mod mod,用二进制快速幂,只保留低位常数。
ll power_mod(ll base, ll exp, ll mod) {
ll res = 1 % mod;
base %= mod;
while (exp > 0) {
if (exp & 1) {
res = res * base % mod;
}
base = base * base % mod;
exp >>= 1;
}
return res;
}
// 高精度数乘以一个较小整数 mult(mult 不超过 1000),结果原地保存在 big[]。
void big_mul_small(ll mult) {
ll carry = 0;
for (ll i = 0; i < big_len; i++) {
ll cur = big[i] * mult + carry;
big[i] = cur % BASE;
carry = cur / BASE;
}
while (carry > 0) {
big[big_len] = carry % BASE;
carry /= BASE;
big_len++;
}
}
// 高精度数整除一个较小整数 divisor(divisor 不超过 100),结果原地保存在 big[]。
void big_div_small(ll divisor) {
ll rem = 0;
for (ll i = big_len - 1; i >= 0; i--) {
ll cur = rem * BASE + big[i];
big[i] = cur / divisor;
rem = cur % divisor;
}
while (big_len > 1 && big[big_len - 1] == 0) {
big_len--;
}
}
// 求组合数 C(M, K)。逐步用 C(M-K+i, i) = C(M-K+i-1, i-1) * (M-K+i) / i 递推,
// 每一步都是整数,避免先算阶乘再做大数除法。
void combination(ll M, ll K) {
big[0] = 1;
big_len = 1;
for (ll i = 1; i <= K; i++) {
big_mul_small(M - K + i);
big_div_small(i);
}
}
// 按高位到低位输出高精度数,低位段补足 9 位前导零。
void print_big() {
printf("%lld", big[big_len - 1]);
for (ll i = big_len - 2; i >= 0; i--) {
printf("%09lld", big[i]);
}
printf("\n");
}
int main() {
ll k, x;
scanf("%lld %lld", &k, &x);
// 第一步:常数项 g(x) = x^x mod 1000。
ll g = power_mod(x, x, MOD_G);
// 第二步:隔板法,a1+...+ak = g(x) 的正整数解组数为 C(g(x)-1, k-1)。
combination(g - 1, k - 1);
print_big();
return 0;
}复杂度
- 时间复杂度:
- 快速幂计算
的时间复杂度为 ; - 计算组合数
时, ,乘除计算次数不超过 次大整数乘除,总运行时间小于 。
- 快速幂计算
- 空间复杂度:
- 仅存储若干中间大整数与输入变量,空间复杂度为
(大整数所占位数),即 常数级内存。
- 仅存储若干中间大整数与输入变量,空间复杂度为
总结
- 利用快速幂计算较小模数下的幂次取模,将大输入
迅速收缩至常数级别 。 - 方程正整数解组数是典型的隔板模型,结论为
。 - 组合数结果达到上百位,采用高精度计算(Python 内置大整数天然支持)。