题目大意: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)项了。
大数取模模版(吉林大学):
1
long 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
6
using namespace std;
7
8
int n;
9
10
long 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
26
int 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