【题解】越狱

题目

题目来源:CCF HNOI2008;

在线评测地址:LG3197

题目描述

监狱有 \(n\) 个房间,每个房间关押一个犯人,有 \(m\) 种宗教,每个犯人会信仰其中一种。如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱。

答案对 \(100,003\) 取模。

输入格式

输入只有一行两个整数,分别代表宗教数 \(m\) 和房间数 \(n\)

输出格式

输出一行一个整数代表答案。

数据规模与约定

对于 \(100\%\) 的数据,保证 \(1\le m\le 10^8\)\(1\le n\le 10^{12}\)

分析

题意很明确,这是一道离散组合计数题,我们要对所有情况进行计数,并且用含有 \(m\)\(n\) 的代数式表示。

这里介绍一种比较容易思考的方法——逆向思维,某些机构将其称为「将错就错」法。

很简单,如果一个问题不好直接计数,那么通过 Ta 的反面来计数。也就是反面情况的补集。

对应到这道题,显然直接求相邻是不太可行的,我们不妨考虑反面,即相邻两两不同。

这就是一个很简单的乘法原理了,对于每一个位置,都有 \(m-1\) 种方案,第一个有 \(m\) 种,则共有 \(m\times (m-1)^{n-1}\) 种。

同时,包括了所有情况的全集 \(|U|=m^n\),所以答案就是 \(m^n-m\times (m-1)^{n-1}\),再用一个快速幂优化即可。

Code

#include <cstdio>
using namespace std;

typedef long long ll;
const int mod = 100003;

ll qp(ll b, ll ind)
{
	ll cur = 1, mul = b, ans = 1;

	while (cur <= ind)
	{
		if (cur & ind)
			ans = ans * mul % mod;
		
		cur <<= 1;
		mul = mul * mul % mod;
	}

	return ans;
}

int main()
{
	ll n, m, tmp, ans;

	scanf("%lld%lld", &m, &n);

	tmp = qp(m, n);
	ans = qp(m - 1, n - 1) * m % mod;

	printf("%lld\n", ((tmp - ans) % mod + mod) % mod);

	return 0;
}
posted @ 2020-07-28 14:27  5ab  阅读(159)  评论(0编辑  收藏  举报