正难则反:答案 = m^n − m(m−1)^(n−1),补集逐位独立相乘,两次模快速幂 O(log n) 出解。
OJ: roj
题目 ID: 1618
难度:普及
标签:数学计数组合计数快速幂python
创建: 2026-09-30 22:18
更新: 2026-10-07 13:50
前置题目
roj 1616「一本通 6.1 练习 1」A 的 B 次方B 在正难则反得到 m^n − m(m−1)^(n−1) 后,直接复用 A 教的三参数 pow 模快速幂算这两个幂,B 的额外台阶是取补集与逐位乘法原理计数。roj 1326【例7.5】取余运算(mod)B 用正难则反得到 m^n−m(m−1)^(n−1) 后,复用 A 教的把指数按二进制拆分求模幂,直接调用 pow 算出两个模幂,只是把 A 的单一幂扩成两个幂;额外台阶是补集计数与乘法原理。luogu P1226【模板】快速幂B 在得出 m^n − m(m−1)^(n−1) 后,直接照 A 教的 Python 三参数 pow 写 pow(m,n,MOD) 与 pow(m-1,n-1,MOD) 求两个模幂,属模板级复用;B 的额外台阶是正难则反取补集加逐位乘法原理的计数。
题目描述
监狱有连续编号为
输入一行两个整数 2 3,样例输出 6。
思路
正难则反:全部状态数为
参考代码
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-09-30 22:18
# update_at: 2026-09-30 22:23
import sys
MOD = 100003 # 题面要求的模数
def solve() -> None:
"""总状态数减掉「相邻房间宗教都不同」的状态数,剩下的就是至少有一对相邻同教的状态数。"""
m, n = map(int, sys.stdin.buffer.read().split())
all_states = pow(m, n, MOD) # 每个房间从 m 种宗教里任选
safe_states = m * pow(m - 1, n - 1, MOD) # 第 1 间任选,之后每间避开左邻的宗教
print((all_states - safe_states) % MOD)
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 01:19
* update_at: 2026-10-06 01:19
*/
#include <cstdio>
typedef long long ll;
const ll MOD = 100003; // 题面要求的模数
ll m, n; // m 种宗教,n 个房间
// 计算 a^b mod MOD,快速幂
ll qpow(ll a, ll b) {
ll res = 1;
a %= MOD;
while (b > 0) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
scanf("%lld %lld", &m, &n);
// 全部状态数 m^n 减去不越狱数 m*(m-1)^(n-1)
// n=1 时没有相邻对,m-1 的 0 次方为 1,公式给出 0,天然正确
ll all_states = qpow(m, n);
ll safe_states = m % MOD * qpow(m - 1, n - 1) % MOD;
// 减法可能出负数,补回模数
ll ans = ((all_states - safe_states) % MOD + MOD) % MOD;
printf("%lld\n", ans);
return 0;
}