您的位置:首页 > 编程语言 > C语言/C++

[BZOJ1008][HNOI2008]越狱

2016-09-18 13:48 218 查看
提交地址

Description

监狱有连续编号为1…N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种。如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱

Input

输入两个整数M,N.1<=M<=10^8,1<=N<=10^12

Output

可能越狱的状态数,模100003取余

Sample Input

2 3

Sample Output

6

HINT

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

思路:

我们弄一个抽象的题意:

有n个盘子,m种荔枝。

每个盘子放一个荔枝,相邻的盘子荔枝种类一样,求方案数。

1<=M<=10^8,1<=N<=10^12

答案模100003

第一个盘子能放m种荔枝,那么第二个盘子呢???

为了不与第一个盘子的荔枝重复,第二个盘子只能放m-1种荔枝。

第三个盘子呢?

为了不与第二个盘子的荔枝重复,第三个盘子也是放m-1种荔枝?

求可能搭配出的方案数。

这不就是小学奥数上的乘法原理嘛!!!

于是我们得出

num=m * (m-1)^(n-1)

这是合法的数量。

总的数量?

all=m^n (这个一眼就看出来了)

ans=all-num

嗯。那直接乘?但很尴尬的是,这个东东太大了1<=M<=10^8,1<=N<=10^12,明显过不了。

在求 a^n 前

我们可以先求出 a^(n/2)

然后 a^(n/2) * a^(n/2) => a^n

这样一直分割下去,我们能得到一个

O(log(n))的算法,名叫快速幂。

代码如下

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;

LL q_mod(LL a,LL b,LL c)
{
LL ans=1%c;a%=c;
while(b)
{
if(b&1)ans=ans*a%100003;
a=a*a%100003;b>>=1;
}
return ans;
}
int main()
{
LL m,n;
scanf("%lld%lld",&m,&n);
LL s=((q_mod(m,n,LL(100003))-m*q_mod(m-1,n-1,LL(100003))%LL(100003)+LL(100003))%LL(100003));
printf("%lld\n",s);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ BZOJ