• 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!

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

  • 相关阅读:
    delphi 缓冲画图(内存画图)解决画图闪烁问题
    多重启动光盘制作
    Delphi源程序格式书写规范
    得到一个数据库的触发器的sql
    Querying Active Directory using .NET classes and LDAP queries(http://www.codeproject.com/dotnet/activedirquery.asp)
    My Friend Blog
    .net good study
    关于javascript的apply和call函数
    Microsoft command
    明基成人礼:巅峰战将营 http://www.cnvn.com.cn/Article/ShowArticle.asp?ArticleID=3172
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/3843628.html
Copyright © 2020-2023  润新知