题目链接
题目描述
监狱有 个房间,每个房间关押一名犯人,共有
种宗教。如果相邻房间的犯人信仰同一种宗教,则可能发生越狱。请求出可能发生越狱的方案总数,结果对
取模。
解题思路
直接计算“至少有一对相邻犯人信仰相同”的方案数比较复杂,需要考虑多种情况并应用容斥原理。一个更简洁的思路是采用补集转化,即正难则反。
补集思想
“可能发生越狱”的对立面是“绝对不会发生越狱”。
- 总方案数:没有任何限制的情况下,每个犯人都有
种宗教选择,且相互独立。根据乘法原理,总的分配方案数为
。
- 不发生越狱的方案数:这种情况要求所有相邻房间的犯人信仰都不同。我们可以从第一个房间开始依次安排:
- 第一个犯人:有
种选择。
- 第二个犯人:为了与第一个犯人不同,只有
种选择。
- 第三个犯人:为了与第二个犯人不同,也只有
种选择。
- ...
- 第
个犯人:为了与第
个犯人不同,同样有
种选择。
。
- 第一个犯人:有
最终公式
根据补集思想,“可能发生越狱”的方案数等于“总方案数”减去“不发生越狱的方案数”。
快速幂
由于 的值可能很大,直接计算幂次会超时。我们需要使用快速幂算法来高效地计算
。快速幂利用了二进制拆分的思想,可以将计算幂的时间复杂度从
优化到
。
在进行减法取模时,需要注意处理结果为负数的情况,标准的处理方式是 (a - b + mod) % mod
。
代码
#include <iostream>
using namespace std;
long long power(long long base, long long exp) {
long long res = 1;
long long mod = 100003;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % mod;
base = (base * base) % mod;
exp /= 2;
}
return res;
}
int main() {
long long m, n;
cin >> m >> n;
long long mod = 100003;
long long total_schemes = power(m, n);
long long no_escape_schemes = (m * power(m - 1, n - 1)) % mod;
long long ans = (total_schemes - no_escape_schemes + mod) % mod;
cout << ans << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static long power(long base, long exp) {
long res = 1;
long mod = 100003;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) {
res = (res * base) % mod;
}
base = (base * base) % mod;
exp /= 2;
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long m = sc.nextLong();
long n = sc.nextLong();
long mod = 100003;
long total_schemes = power(m, n);
long no_escape_schemes = (m * power(m - 1, n - 1)) % mod;
long ans = (total_schemes - no_escape_schemes + mod) % mod;
System.out.println(ans);
}
}
def power(base, exp):
res = 1
mod = 100003
base %= mod
while exp > 0:
if exp % 2 == 1:
res = (res * base) % mod
base = (base * base) % mod
exp //= 2
return res
m, n = map(int, input().split())
mod = 100003
total_schemes = power(m, n)
no_escape_schemes = (m * power(m - 1, n - 1)) % mod
ans = (total_schemes - no_escape_schemes + mod) % mod
print(ans)
算法及复杂度
-
算法:组合数学、补集思想、快速幂
-
时间复杂度:主要开销来自于两次快速幂运算,每次的复杂度为
。因此,总时间复杂度为
。
-
空间复杂度:只使用了常数个变量,空间复杂度为
。