题解 P4000 【斐波那契数列】

· · 题解

来篇Pascal题解。

对于这道题,Pascal的读入效率不用说,但是动态字符串真是太丢人了……

毕竟是用链表实现的,访问的时候不慢才怪

TLE后3个点。

果断使用字符数组。

没有strlen这样的东西,就一个一个遍历下来,不是数字就退出。

AC。

具体实现不讲了,就是求循环节然后矩阵快速幂。

求循环节什么的看这里:Fib数模n的循环节

如果看懂了写代码也不难了。(也就是模拟嘛)

丢代码:

type
  matrix=array[1..2,1..2]of int64;//因为p太大要开int64
var
  a1,t1:array[1..60000]of longint;
  i,p,num:longint;
  x,s:int64;
  a,t:matrix;
  n:array[0..30000001]of char; //坑点:一定要多出一位(我也不知道为什么,但是WA了好几次)
function gcd(x,y:int64):int64; //不解释
var
  r:int64;
begin
  while y>0 do
  begin
    r:=x mod y;
    x:=y;
    y:=r;
  end;
  exit(x);
end;
function lcm(x,y:int64):int64; //不解释
begin
  exit(x div gcd(x,y)*y);
end;
function solve(x:longint):int64;//求解循环节
var
  i:longint;
begin
  for i:=2 to trunc(sqrt(x)) do
    if x mod i=0 then
    begin
      inc(num);
      a1[num]:=1;
      t1[num]:=i;
      x:=x div i;
      while x mod i=0 do
      begin
        x:=x div i;
        a1[num]:=a1[num]*i;
      end;
    end;
  if x>1 then
  begin
    inc(num);
    a1[num]:=1;
    t1[num]:=x;
  end;
  solve:=1;
  for i:=1 to num do
    case t1[i] of
    2:solve:=lcm(solve,int64(a1[i])*3);
    3:solve:=lcm(solve,int64(a1[i])*5);
    5:solve:=lcm(solve,int64(a1[i])*20);
    else if (t1[i] mod 5=1) or (t1[i] mod 5=4) then
    solve:=lcm(solve,int64(a1[i])*(t1[i]-1))
    else
    solve:=lcm(solve,int64(a1[i])*((t1[i]+1) shl 1));
  end;
end;
operator *(a,b:matrix)c:matrix;//矩阵乘法的实现
begin
  c[1,1]:=(a[1,1]*b[1,1] mod p+a[1,2]*b[2,1] mod p) mod p;
  c[1,2]:=(a[1,1]*b[1,2] mod p+a[1,2]*b[2,2] mod p) mod p;
  c[2,1]:=(a[2,1]*b[1,1] mod p+a[2,2]*b[2,1] mod p) mod p;
  c[2,2]:=(a[2,1]*b[1,2] mod p+a[2,2]*b[2,2] mod p) mod p;
end;
function power(x:matrix;y:int64):matrix;//矩阵快速幂
begin
  power[1,1]:=1;
  power[2,2]:=1;
  while y>0 do
  begin
    if odd(y) then
      power:=power*x;
    x:=x*x;
    y:=y shr 1;
  end;
end;
begin                          //简单的主程序
  readln(n);
  read(p);
  if p=1 then                  //特判啦啦啦
  begin
    writeln(0);
    halt;
  end;
  x:=solve(p);
  s:=0;
  for i:=0 to 30000001 do      //Pascal用char读入会超时……只好这样读入后取模了
    if (n[i]>='0') and (n[i]<='9') then
      s:=(s*10+ord(n[i])-48) mod x
    else
      break;
  if s=0 then                  //斐波那契数列特判
  begin
    writeln(0);
    halt;
  end;
  if s<=2 then
  begin
    writeln(1);
    halt;
  end;
  a[1,1]:=1;                  //矩阵快速幂啦啦啦
  a[1,2]:=1;
  a[2,1]:=1;
  a[2,2]:=0;
  t:=power(a,s-2);
  writeln((t[1,1]+t[1,2]) mod p);
end.