[HNOI2008]越狱(思路+题解)
快速幂+组合数学
题目链接https://www.luogu.org/problemnew/show/P3197
题目大意:N个格子,用M个数字填,且必须填满,求出相邻格子中数字一样的方案数,输出结果对100003取余。
输入样例:
2 3
输出样例
6
样例解释
6种状态为(000)(001)(011)(100)(110)(111)
数据范围
1≤M≤10^8
1≤N≤10^12
解题思路:一开始我是想的看能不能套组合的公式,然而并没有套出来,然后就去思考每一个格子能够填数字的方案数。
但是如果正面去做的话,方案数很多,没有办法考虑全,那就容斥一下就行了,正难则反嘛...
于是问题就变成了求出相邻格子中的数字不一样的方案数,第一个格子的方案数为M,它什么都可以填,
第二个格子的数为了保证与第一个数不同,方案数为M-1,不难发现,之后的每个格子的方案数都为M-1,
所以根据乘法原理,不合法的方案数为M*(M-1)^(n-1)。而总的方案数怎么算呢?很简单,每个格子都可以填M个中的任意一个数字,即总方案数为M^n。
我们要输出的答案就是M^n-M*(M-1)^(n-1),当然,还要取模。
N和M的范围很大,所以用快速幂解决。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define ll long long int using namespace std; ll n,m,ans,mod=100003; ll power(ll b,ll p){ ll tot=1; while(p){ if(p&1){ tot=(tot*b)%mod; } p>>=1; b=(b*b)%mod; } return tot%mod; } int main() { scanf("%lld%lld",&m,&n); ans=(power(m,n)%mod-(m*power(m-1,n-1))%mod+mod)%mod; printf("%lld",ans%mod); return 0; }