CodeForces 185A 快速幂

  一开始找矩阵快速幂的题来做时就看到了这题,题意就是让你求出如图所示的第n个三角形中指向向上的小三角形个数。从图中已经很容易看出递推关系了,我们以f[n]表示第n个大三角形中upward的小三角形个数,g[n]表示第n个大三角形中downward的小三角形个数,然后,递推关系就是:

  f[n]= 3*f[n-1]+1*g[n-1];        (1)

  g[n]= 3*g[n-1]+1*f[n-1];         (2)

其中f[0]= 1,g[0]= 0(一开始的纯三角形是从n=0开始的),然后……就没有然后了,直觉上感觉f[n]很难表示成只含有f[i]的式子,一时没想到该如何再和矩阵联系起来了(实际上两个不同的变量还是能构造出矩阵出来的:[ f(n), g(n) ]T= [ [3,1], [1,3] ]* [ f(n-1), g(n-1) ]T 即可,该矩阵就是 [ [3,1], [1,3] ]T,在这里写矩阵毕竟很不方便,自己在草稿纸上写出来看看吧,更直观),当时一时脑子发热没往这个方向去想,于是便转向了第二个思路。

  (现在回来补充一点点,其实以上两个式子也可以推出 f[n]的方程来了:(1)+(2) 得到 f[n]+g[n]= 4*(f[n-1]+g[n-1]),因为f[1]=3,g[1]=1,f[1]+g[1]=4,所以f[n]+g[n]= 4n;同理,(1)-(2) 得到 f[n]-g[n]= 2*(f[n-1]-g[n-1]),f[1]-g[1]= 3-1=2,故f[n]+g[n]= 2n,所以 f[n]= ( (f[n]+g[n])+ (f[n]-g[n]) ) /2= (4n+2n)/2= (2n+1)*2n-1,和下面看图思考出的相同 )

  我再次观察了图发现它的确很有规律,无论是f[n]还是g[n]都是 1+2+3+……+k 的和嘛,k就是大三角形的层数,而层数也很有规律,第n个三角形的层数是前一个的两倍(也不难看出,因为每个子三角形每次都划分为两层),所以k= 2n,所以f[n]= (1+2n)*2n-1,g[n]也很容易表示出来,不过此时已经不需要g[n]了,之后,便是一个简简单单的裸快速幂即可!

 1 #include<cstdio>
 2 typedef long long LL;
 3 const LL mod= 1000000007;
 4 
 5 LL quick_mod(LL a, LL b, LL m){
 6     LL ans= 1;
 7     a%= m;
 8     while(b){
 9         if(b&1)      ans= ans*a%m;
10         a= a*a%m;
11         b>>=1;
12     }
13     return ans;
14 }
15 
16 int main(){
17     LL n;
18     scanf("%I64d",&n);
19     if(!n)    puts("1");
20     else    printf("%I64d\n",(1+quick_mod(2,n,mod))*quick_mod(2,n-1,mod)%mod);
21     return 0;
22 }

  后来我把输入改成 while(~scanf(....)) 来试了下,也过了,可以看出cf上是单组数据读入的,即便这样用while也行,注意添加好文件结束符EOF即可。

  水过后,我看着1000000007这个数值觉得用long long来处理好像也是有点浪费了,相乘是会溢出,但相加绝对不会溢出,只是已经很接近 int的上限而已。于是,我装了下B,把快速幂中的相乘改为了相加(同样利用快速幂的原理,二进制处理连续的加),这样,就能避开了long long(虽说节省不了什么资源,但可以训练下处理数据溢出的一些能力。不过在比赛中还是绝对不要这样给自己找麻烦,保险才是最重要的),写好快速乘取模后,却忘了在最后的 (1+2n)*2n-1 这里还有一个乘法,所以也调试了一点点时间。

 1 #include<cstdio>
 2 typedef long long LL;
 3 const int mod= 1000000007;
 4 
 5 int quick_mul(int a, int b, int m){
 6     int ans= 0;
 7     a%= m;
 8     while(b){
 9         if(b&1)      ans= (ans+a)%m;
10         a= (a+a)%m;
11         b>>=1;
12     }
13     return ans;
14 }
15 
16 int quick_mod(int a, LL b, int m){
17     int ans= 1;
18     a%= m;
19     while(b){
20         if(b&1)      ans= quick_mul(ans,a,m);
21         a= quick_mul(a,a,m);
22         b>>=1;
23     }
24     return ans;
25 }
26 
27 int main(){
28     LL n;
29     while(~scanf("%I64d",&n)){
30         if(!n)    puts("1");
31         else {
32             int tmp1= quick_mod(2,n-1,mod);
33             int tmp2= tmp1*2%mod;
34             printf("%d\n",quick_mul((1+tmp2),tmp1,mod));
35         }
36     }
37     return 0;
38 }

  至此,装逼完成,成功水过。

posted @ 2014-12-19 13:13  Newdawn_ALM  阅读(393)  评论(0编辑  收藏  举报