[HNOI2008]越狱(思路+题解)

快速幂+组合数学

题目链接https://www.luogu.org/problemnew/show/P3197

题目大意:N个格子,用M个数字填,且必须填满,求出相邻格子中数字一样的方案数,输出结果对100003取余。

输入样例:

2 3

输出样例

6

样例解释

6种状态为(000)(001)(011)(100)(110)(111)

数据范围

1M10^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;
}

猜你喜欢

转载自www.cnblogs.com/sky-zxz/p/9510475.html