越狱(信息学奥赛一本通 1618)
【题目描述】
原题来自:HNOI 2008
监狱有连续编号为 1 到 n 的 n 个房间,每个房间关押一个犯人。有 m 种宗教,每个犯人可能信仰其中一种。如果相邻房间的犯人信仰的宗教相同,就可能发生越狱。求有多少种状态可能发生越狱。
【输入】
输入两个整数 m 和 n。
【输出】
可能越狱的状态数,对 100003 取余。
【输入样例】
2 3
【输出样例】
6
【提示】
样例说明
6 种状态为:{0,0,0},{0,0,1},{0,1,1},{1,0,0},{1,1,0},{1,1,1}。
数据范围与提示:
对于全部数据,1≤m≤108,1≤n≤1012 。
当然一开始我并没有想到可以用快速幂的方法,看到题目以后马上联想到DP啥子的,然鹅事实证明用快速幂最为简便
直接正面刚去求有多少种状态的话肯定是会爆掉而且还没有什么好方法,那么正难则反,我们可以通过用总状态数-不会越狱的状态数来得到答案
并且不难发现,总状态数=m^n,不会越狱的状态数=(m-1)^(n-1)*m(乘法原理,第一个监狱的犯人可能有m种状态,而与其相邻的第二个监狱就只能有m-1种状态,同理,其余的监狱也只能有m-1种状态),这样的话,用快速幂就特别方便啦!(σ゚∀゚)σ..:*☆
代码走一波:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const long long M=100003; 4 long long m,n;//这道题基本上都是用long long类型,不然会像我一样被卡5个点死活过不去ε(┬┬﹏┬┬)3 5 long long read() 6 { 7 long long x=0,f=1; 8 char ch=getchar(); 9 while(ch<'0'||ch>'9') 10 { 11 if(ch=='-') f=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9') 15 { 16 x=x*10+ch-'0'; 17 ch=getchar(); 18 } 19 return x*f; 20 } 21 void write(int x) 22 { 23 if(x<0) 24 { 25 putchar('-'); 26 x=-x; 27 } 28 if(x>9) write(x/10); 29 putchar(x%10+'0'); 30 } 31 32 long long ff(long long x,long long y) 33 { 34 long long ans=1; 35 while(y) 36 { 37 if(y&1)ans=ans*x%M; 38 x=x*x%M; 39 y>>=1; 40 } 41 return ans; 42 } 43 int main() 44 { 45 m=read();n=read(); 46 if(n<2)return 0*puts("0"); 47 printf("%lld\n",((ff(m,n)-m*ff(m-1,n-1)%M)%M+M)%M); 48 return 0; 49 }