• NOI2013矩阵游戏


    Description

    婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:

    F[1][1]=1
    F[i,j]=a*F[i][j-1]+b (j!=1)
    F[i,1]=c*F[i-1][m]+d (i!=1)
    递推式中a,b,c,d都是给定的常数。

    现在婷婷想知道F[n][m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F[n][m]除以1,000,000,007的余数。
    Input

    一行有六个整数n,m,a,b,c,d。意义如题所述
    Output

    包含一个整数,表示F[n][m]除以1,000,000,007的余数
    Sample Input
    3 4 1 3 2 6
    Sample Output
    85
    HINT

    样例中的矩阵为:

    1 4 7 10

    26 29 32 35

    76 79 82 85

    题解:

    不看数据范围的话这就是到水题……

    前10个点很好过,普通的二进制快速幂就可以  

    后面10个点如果还用原来的方法,需要涉及高精度除以单精度,复杂度是O(len)的

    所以一种新的快速幂诞生了!-----十进制快速幂!

    (转)

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    假设咱们需要求 m^n,咱们有一种方法是 二进制快速幂,这个的复杂度是O(logn)的。但是咱们还可以做的更好实际上....咱们把 n拆成10进制表达式,比如 :
    234=2*10^2+3*10+4,
    139476=1*10^5+3*10^4+9*10^3+4*10^2+7*10^1+6
    咱们设拆成的形式是
    n=a0+a1*10^1+a2*10^2...+ai*10^i+...+ad*10^d,d为n的最高位,其实就是d=【logn】(log以10为底数)
    然后这个表示出来了咱们有:
    m^n=m^(a0+a1*10^1+a2*10^2+...+ai*10^i...+ad*10^d)(ak∈【0,9】,k∈【1,d】)
    看出一点来了吧...
    咱们可以化成 m^n=m^a9*(m^a1)^10*(m^a2)^100....
    继续化简,咱们有 m^n=(((m^ad)^10*ad-1)^10*m^ad-2).....
    这个实际上就很好做了,由于 0<=ai<=9,只需要预处理下m^0~m^9即可很快计算出m^ai,然后这个就是O(logn)的,(log以10为底),只不过需要加个10的常数,不过这个的效率在n达到10^100就可以体现了=w=。
    即算法流程就是初始化ans=1,从n的最高位开始,每一次提取一位w,用ans乘以m^w然后再做10次的幂,重复到n的所有位都取完了即可。即这个算法的复杂度只与n的位数有关,预处理10个数复杂度也不是很高。
    然后取最高位只需要一开始分解每个位存在一个数组里面即可,这里假设是a[],然后预处理的m^0~9在mm[]里,下面就是伪代码:
     
    function quickmod(n:int64):int64;
    begin
        len=0;tmp=n
        while tmp!=0 do
            len=len+1
           a[len]=tmp mod 10;
           tmp=tmp div 10;
        ans=1
        for i=len downto 1 do
          ans=ans*mm[a[i]]
          ans=ans^10
        return ans
    end
        

    再举个例子吧...

    比如 2^154,咱们就有 2^154=((2^1)^10*2^5)^10*2^4 咱们拆开来自然可以检验出这个是不是正确的了。
    再比如 2^1512526,咱们就有
    2^1512526=((((((2^1)^10*2^5)^10*2^1)^10*2^2)^10*2^5)^10*2^2)^10*2^6
    为什么要用十进制快速幂?显然可以发现它的表示实际上比二进制更自然吧...每次只需要取最高位就可以了而不需要考虑什么二进制的原理,显然是十分方便的。而且复杂度比二进制的复杂度更小,还是非常不错了。
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    我觉得其实十进制快速幂的思想和霍纳法则(或者称之为秦九韶算法)差不多……
    代码1:50分 二进制快速幂
     1 const p=1000000007;
     2 type matrix=array[1..2,1..2] of longint;
     3 var a,b,c:matrix;
     4     i,n,m,a1,a2,b1,b2:longint;
     5 procedure mul(var x,y,z:matrix);
     6  var t:matrix;
     7      i,j,k:longint;
     8  begin
     9  fillchar(t,sizeof(t),0);
    10  for i:=1 to 2 do
    11   for j:=1 to 2 do
    12    for k:=1 to 2 do
    13     t[i,j]:=(t[i,j]+x[i,k]*y[k,j]) mod p;
    14  z:=t;
    15  end;
    16 procedure ksm(cs:longint);
    17  begin
    18  while cs>0 do
    19   begin
    20   if cs and 1=1 then mul(a,b,b);
    21   cs:=cs>>1;
    22   mul(a,a,a);
    23   end;
    24  end;
    25 procedure init;
    26  begin
    27  readln(n,m,a1,b1,a2,b2);
    28  end;
    29 procedure main;
    30  begin
    31  a[1,1]:=1;a[1,2]:=b1;a[2,1]:=0;a[2,2]:=a1;
    32  for i:=1 to 2 do b[i,i]:=1;
    33  ksm(m-1);
    34  c:=b;
    35  b[1,1]:=1;b[1,2]:=b2;b[2,1]:=0;b[2,2]:=a2;
    36  mul(c,b,a);
    37  fillchar(b,sizeof(b),0);
    38  for i:=1 to 2 do b[i,i]:=1;
    39  ksm(n-1);
    40  mul(b,c,b);
    41  writeln((b[1,2]+b[2,2]) mod p);
    42  end;
    43 begin
    44  init;
    45  main;
    46 end.
    View Code

    代码2:80分 十进制快速幂(后四个点TLE)

     1 const p=1000000007;
     2 type matrix=array[1..2,1..2] of longint;
     3      arrtype=array[0..1500000] of longint;
     4 var a,b,c:matrix;
     5     mm:array[0..9] of matrix;
     6     i,a1,a2,b1,b2:longint;
     7     n,m:arrtype;
     8     ch:char;
     9 procedure mul(var x,y,z:matrix);
    10  var t:matrix;
    11      i,j,k:longint;
    12  begin
    13  fillchar(t,sizeof(t),0);
    14  for i:=1 to 2 do
    15   for j:=1 to 2 do
    16    for k:=1 to 2 do
    17     t[i,j]:=(t[i,j]+x[i,k]*y[k,j]) mod p;
    18  z:=t;
    19  end;
    20 procedure pow10(s:arrtype);
    21  var i,j:longint;t:matrix;
    22  begin
    23  dec(s[s[0]]);i:=s[0];while s[i]<0 do begin inc(s[i],10);dec(s[i-1],1);dec(i);end;
    24  fillchar(mm,sizeof(mm),0);
    25  for i:=1 to 2 do mm[0,i,i]:=1;
    26  for i:=1 to 9 do mul(mm[i-1],a,mm[i]);
    27  fillchar(b,sizeof(b),0);
    28  for i:=1 to 2 do b[i,i]:=1;
    29  for i:=1 to s[0] do
    30   begin
    31   mul(b,mm[s[i]],b);
    32   if i=s[0] then break;
    33   t:=b;
    34   for j:=2 to 10 do mul(b,t,b);
    35   end;
    36  end;
    37 procedure init;
    38  begin
    39  read(ch);n[0]:=0;
    40  while ch<>' ' do
    41    begin
    42    inc(n[0]);n[n[0]]:=ord(ch)-ord('0');
    43    read(ch);
    44    end;
    45  read(ch);m[0]:=0;
    46  while ch<>' ' do
    47    begin
    48    inc(m[0]);m[m[0]]:=ord(ch)-ord('0');
    49    read(ch);
    50    end;
    51  readln(a1,b1,a2,b2);
    52  end;
    53 procedure main;
    54  begin
    55  a[1,1]:=1;a[1,2]:=b1;a[2,1]:=0;a[2,2]:=a1;
    56  pow10(m);
    57  c:=b;
    58  b[1,1]:=1;b[1,2]:=b2;b[2,1]:=0;b[2,2]:=a2;
    59  mul(c,b,a);
    60  pow10(n);
    61  mul(b,c,b);
    62  writeln((b[1,2]+b[2,2]) mod p);
    63  end;
    64 begin
    65  init;
    66  main;
    67 end.
    View Code

    代码3:80分 考虑把代码二中 ans^10换成二进制快速幂(依然TLE)

     1 const p=1000000007;
     2 type matrix=array[1..2,1..2] of int64;
     3      arrtype=array[0..1500000] of longint;
     4 var a,b,c:matrix;
     5     mm:array[0..9] of matrix;
     6     i,a1,a2,b1,b2:longint;
     7     n,m:arrtype;
     8     ch:char;
     9 procedure mul(var x,y,z:matrix);
    10  var t:matrix;
    11      i,j,k:longint;
    12  begin
    13  fillchar(t,sizeof(t),0);
    14  for i:=1 to 2 do
    15   for j:=1 to 2 do
    16    for k:=1 to 2 do
    17     t[i,j]:=(t[i,j]+x[i,k]*y[k,j]) mod p;
    18  z:=t;
    19  end;
    20 procedure pow10(s:arrtype);
    21  var i,j,cs:longint;tmp:matrix;
    22  begin
    23  dec(s[s[0]]);i:=s[0];while s[i]<0 do begin inc(s[i],10);dec(s[i-1],1);dec(i);end;
    24  fillchar(mm,sizeof(mm),0);
    25  for i:=1 to 2 do mm[0,i,i]:=1;
    26  for i:=1 to 9 do mul(mm[i-1],a,mm[i]);
    27  fillchar(b,sizeof(b),0);
    28  for i:=1 to 2 do b[i,i]:=1;
    29  for i:=1 to s[0] do
    30   begin
    31   mul(b,mm[s[i]],b);
    32   if i=s[0] then break;
    33   tmp:=b;
    34   fillchar(b,sizeof(b),0);
    35   for j:=1 to 2 do b[j,j]:=1;
    36   cs:=10;
    37   while cs>0 do
    38    begin
    39    if cs and 1=1 then mul(tmp,b,b);
    40    cs:=cs>>1;
    41    mul(tmp,tmp,tmp);
    42    end;
    43   end;
    44  end;
    45 procedure init;
    46  begin
    47  read(ch);n[0]:=0;
    48  while ch<>' ' do
    49    begin
    50    inc(n[0]);n[n[0]]:=ord(ch)-ord('0');
    51    read(ch);
    52    end;
    53  read(ch);m[0]:=0;
    54  while ch<>' ' do
    55    begin
    56    inc(m[0]);m[m[0]]:=ord(ch)-ord('0');
    57    read(ch);
    58    end;
    59  readln(a1,b1,a2,b2);
    60  end;
    61 procedure main;
    62  begin
    63  a[1,1]:=1;a[1,2]:=b1;a[2,1]:=0;a[2,2]:=a1;
    64  pow10(m);
    65  c:=b;
    66  b[1,1]:=1;b[1,2]:=b2;b[2,1]:=0;b[2,2]:=a2;
    67  mul(c,b,a);
    68  pow10(n);
    69  mul(b,c,b);
    70  writeln((b[1,2]+b[2,2]) mod p);
    71  end;
    72 begin
    73  init;
    74  main;
    75 end.     
    View Code

    代码4:受兰多夫87的影响,考虑修改矩阵乘法,应为第一列始终是不变的  (为什么还是TLE啊…………)

     1 const p=1000000007;
     2 type matrix=array[1..2,1..2] of int64;
     3      arrtype=array[0..1500000] of longint;
     4 var a,b,c:matrix;
     5     mm:array[0..9] of matrix;
     6     i,a1,a2,b1,b2:longint;
     7     n,m:arrtype;
     8     ch:char;
     9 procedure mul(var x,y,z:matrix);
    10  var t:matrix;
    11      i,j,k:longint;
    12  begin
    13  fillchar(t,sizeof(t),0);
    14  t[1,1]:=1;t[2,1]:=0;
    15  for i:=1 to 2 do
    16    for k:=1 to 2 do
    17     t[i,2]:=(t[i,2]+x[i,k]*y[k,2]) mod p;
    18  z:=t;
    19  end;
    20 procedure pow10(s:arrtype);
    21  var i,j,cs:longint;tmp:matrix;
    22  begin
    23  dec(s[s[0]]);i:=s[0];while s[i]<0 do begin inc(s[i],10);dec(s[i-1],1);dec(i);end;
    24  fillchar(mm,sizeof(mm),0);
    25  for i:=1 to 2 do mm[0,i,i]:=1;
    26  for i:=1 to 9 do mul(mm[i-1],a,mm[i]);
    27  fillchar(b,sizeof(b),0);
    28  for i:=1 to 2 do b[i,i]:=1;
    29  for i:=1 to s[0] do
    30   begin
    31   mul(b,mm[s[i]],b);
    32   if i=s[0] then break;
    33   tmp:=b;
    34   fillchar(b,sizeof(b),0);
    35   for j:=1 to 2 do b[j,j]:=1;
    36   cs:=10;
    37   while cs>0 do
    38    begin
    39    if cs and 1=1 then mul(tmp,b,b);
    40    cs:=cs>>1;
    41    mul(tmp,tmp,tmp);
    42    end;
    43   end;
    44  end;
    45 procedure init;
    46  begin
    47  read(ch);n[0]:=0;
    48  while ch<>' ' do
    49    begin
    50    inc(n[0]);n[n[0]]:=ord(ch)-ord('0');
    51    read(ch);
    52    end;
    53  read(ch);m[0]:=0;
    54  while ch<>' ' do
    55    begin
    56    inc(m[0]);m[m[0]]:=ord(ch)-ord('0');
    57    read(ch);
    58    end;
    59  readln(a1,b1,a2,b2);
    60  end;
    61 procedure main;
    62  begin
    63  a[1,1]:=1;a[1,2]:=b1;a[2,1]:=0;a[2,2]:=a1;
    64  pow10(m);
    65  c:=b;
    66  b[1,1]:=1;b[1,2]:=b2;b[2,1]:=0;b[2,2]:=a2;
    67  mul(c,b,a);
    68  pow10(n);
    69  mul(b,c,b);
    70  writeln((b[1,2]+b[2,2]) mod p);
    71  end;
    72 begin
    73  init;
    74  main;
    75 end.      
    76             
    View Code

    代码5:我认为是我写丑了 膜拜兰多夫87吧

     1 const p=1000000007;
     2 type matrix=array[1..2] of int64;
     3      arrtype=array[0..1500000] of longint;
     4 var x,y:matrix;
     5     z:array[0..9] of matrix;
     6     i,a,b,c,d:longint;
     7     n,m:arrtype;
     8     ch:char;
     9 operator *(a,b:matrix)c:matrix;
    10  begin
    11  c[1]:=a[1]*b[1] mod p;
    12  c[2]:=(b[1]*a[2]+b[2]) mod p;
    13  end;
    14 function f(x:matrix;var a:arrtype):matrix;
    15  var i:longint;y:matrix;
    16  begin
    17  dec(a[a[0]]);i:=a[0];
    18  while a[i]<0 do begin inc(a[i],10);dec(a[i-1]);dec(i);end;
    19  z[0,1]:=1;z[0,2]:=0;
    20  for i:=1 to 9 do z[i]:=z[i-1]*x;
    21  x:=z[0];
    22  for i:=1 to a[0] do
    23   begin
    24   y:=x*x;
    25   x:=x*y*y;
    26   x:=x*x;
    27   x:=x*z[a[i]];
    28   end;
    29  exit(x);
    30  end;
    31 procedure init;
    32  begin
    33  read(ch);n[0]:=0;
    34  while ch<>' ' do
    35    begin
    36    inc(n[0]);n[n[0]]:=ord(ch)-ord('0');
    37    read(ch);
    38    end;
    39  read(ch);m[0]:=0;
    40  while ch<>' ' do
    41    begin
    42    inc(m[0]);m[m[0]]:=ord(ch)-ord('0');
    43    read(ch);
    44    end;
    45  readln(a,b,c,d);
    46  end;
    47 procedure main;
    48  begin
    49  x[1]:=a;x[2]:=b;
    50  x:=f(x,m);
    51  y[1]:=c;y[2]:=d;
    52  y:=x*y;
    53  y:=f(y,n);
    54  y:=y*x;
    55  writeln((y[1]+y[2]) mod p);
    56  end;
    57 begin
    58  assign(input,'matrix.in');assign(output,'matrix.out');
    59  reset(input);rewrite(output);
    60  init;
    61  main;
    62  close(input);close(output);
    63 end.   
    View Code

    无限orz!

    看来养成一个好的代码风格是必要的

  • 相关阅读:
    Poj 1742 Coins(多重背包)
    Poj 2350 Above Average(精度控制)
    求二进制数中1的个数
    Poj 1659 Distance on Chessboard(国际象棋的走子规则)
    Poj 2411 Mondriaan's Dream(压缩矩阵DP)
    Poj 2136 Vertical Histogram(打印垂直直方图)
    Poj 1401 Factorial(计算N!尾数0的个数——质因数分解)
    poj 2390 Bank Interest(计算本利和)
    Poj 2533 Longest Ordered Subsequence(LIS)
    Poj 1887 Testing the CATCHER(LIS)
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/3843628.html
Copyright © 2020-2023  润新知