题目大意:Pupu有N层皮,每一层要么是透明,要么是不透明的,每天被太阳晒到的就会变一次,设N层刚出生都不透明,要全部皮都至少变过一次要多少天?(答案MOD N)
解题思路:1)理解题目:
注意注意,题目所求的是每层皮肤至少变一次的天数,不是全部变成透明的天数!...
.坑爹的,它里面写的是(that all of a PuPu's skins has been changed from opacity to clarity )
2)设f[n]为前n层皮肤变成透明所需要的天数,ans[n]为全部皮肤至少变一次的天数。
易得:f[n]=2*f[n-1];
ans[n]=f[n-1]+1; ==>ans[n]=2^(n-1)+1;
f[1]=2 (0->1 两天);
3)这里ans的增长率很客观,所以答案要进行取模,便涉及到一个大数取模((logb)^3)的运算。
1、首先将b化为二进制数:即b=(AtAt-1At-2.....A0)2=At*2^t+At-1*2^(t-1).....+A0;
2、a^b % c = a^(At*2^t+At-1*2^(t-1)+.....+A0)%c=((a^(At*2^t))%c*(a^(A(t-1)*2^(t-1)))%c*.......*(a^(A0)%c))
(*....这式子看起来好恶心......*)
3、对于每一个a^(2^(i+1))%c=(a^(2^i)%c)^2%c
这样我们就可以在常数时间内由2^n项推到2^(n+1)项了。
大数取模模版(吉林大学):
1long long mod_exp(long long a,long long b0,long long n)
2{
3 if( a > n ) a %= n;
4 long long i, d = 1, b[35];
5 for( i=0; i < 35; ++i ){
6 b[i] = b0%2;
7 b0 /= 2;
8 if( b0 == 0 ) break;
9 }
10 for( ;i >= 0; --i ){
11 d = (d*d)%n;
12 if( b[i] == 1 ) d = (d*a)%n;
13 }
14 return d;
15}
代码:
1#include <iostream>
2#include <cstdio>
3#include <cstring>
4#include <cmath>
5
6using namespace std;
7
8int n;
9
10long long mod_exp(long long a,long long b0,long long n)
11{
12 if( a > n ) a %= n;
13 long long i, d = 1, b[35];
14 for( i=0; i < 35; ++i ){
15 b[i] = b0%2;
16 b0 /= 2;
17 if( b0 == 0 ) break;
18 }
19 for( ;i >= 0; --i ){
20 d = (d*d)%n;
21 if( b[i] == 1 ) d = (d*a)%n;
22 }
23 return d;
24}
25
26int main()
27{
28 while(~scanf("%d",&n))
29 {
30 if(n == 0) break;
31 printf("%I64d\n",(mod_exp(2,(n-1),n)+1)%n);
32 }
33 return 0;
34}
35