2021/3/17算法题打卡

斐波那契变题

标题:斐波那契

斐波那契数列大家都非常熟悉。它的定义是:

f(x) = 1 .... (x=1,2)
f(x) = f(x-1) + f(x-2) .... (x>2)

对于给定的整数 n 和 m,我们希望求出:
f(1) + f(2) + ... + f(n) 的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
公式参见【图1.png】

但这个数字依然很大,所以需要再对 p 求模。

【数据格式】
输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)
输出为1个整数

例如,如果输入:
2 3 5
程序应该输出:
0

再例如,输入:
15 11 29
程序应该输出:
25

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

方法一:

解析:

f(x) = f(x-1)+f(x-2)-->f(x+1)=f(x)+f(x-1)-->f(x+1)-f(x-1)
Σf(n) = f(n+2)-1
原题目等价于:(f(n+2)-1)%f(m)%p --> m>=n+2,余f(m)无意义
-->(f(n+2)-1)%p
(f(n+2)-1)%f(m)%p --> m<n+2

40分

代码:


public class T9斐波那契 {

    static int n;
    static int m;
    static int p;

    static Long[] longs;


    private static BigInteger fib(int k) {
        for(int i=3;i<=k;i++){
            longs[i]=longs[i-1]+longs[i-2];
        }
        return BigInteger.valueOf(longs[k]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        n = scanner.nextInt();
        m = scanner.nextInt();
        p = scanner.nextInt();

        longs = new Long[n+3];
        longs[1]=Long.valueOf(1);
        longs[2]=Long.valueOf(1);

        BigInteger sum=fib(n+2);

        if(m>=n+2) {
            sum = sum.subtract(BigInteger.ONE);
            sum = sum.mod(BigInteger.valueOf(p));
            System.out.println(sum);
        }else{
            BigInteger numB = BigInteger.valueOf(longs[m]);
            sum = sum.mod(numB);
            sum = sum.mod(BigInteger.valueOf(p));
            sum = sum.subtract(BigInteger.ONE);
        }

        System.out.println(sum);

    }

}

但是本方法对于10^18次方的数据来说,一是超时,二是long无法存下这么大的数据,所以最终只能得40分

方法二:

解析

可以通过矩阵快速幂来得到结果,这是最快的解法 O(logn),用该方法可以解决超时问题
矩阵解法:

60分

代码:

public class T9斐波那契2 {

    static long n;
    static long m;
    static long p;

    //矩阵相乘
    public static M mul(M m1,M m2){
        M ans = new M();
        ans.data[0][0]=m1.data[0][0]*m2.data[0][0]+m1.data[0][1]*m2.data[1][0];
        ans.data[0][1]=m1.data[0][0]*m2.data[0][1]+m1.data[0][1]*m2.data[1][1];
        ans.data[1][0]=m1.data[1][0]*m2.data[0][0]+m1.data[1][1]*m2.data[1][0];
        ans.data[1][1]=m1.data[1][0]*m2.data[0][1]+m1.data[1][1]*m2.data[1][1];
        return ans;
    }

    //矩阵相乘
    public static M mul(M m1,M m2,long mod){
        M ans = new M();
        ans.data[0][0]=((m1.data[0][0]*m2.data[0][0])%mod+(m1.data[0][1]*m2.data[1][0])%mod)%mod;
        ans.data[0][1]=((m1.data[0][0]*m2.data[0][1])%mod+(m1.data[0][1]*m2.data[1][1])%mod)%mod;
        ans.data[1][0]=((m1.data[1][0]*m2.data[0][0])%mod+(m1.data[1][1]*m2.data[1][0])%mod)%mod;
        ans.data[1][1]=((m1.data[1][0]*m2.data[0][1])%mod+(m1.data[1][1]*m2.data[1][1])%mod)%mod;
        return ans;
    }

    //m的m次幂
    public static M mPow(M m,long n){
        M E = new M();//单位矩阵
        E.data[0][0]=1;
        E.data[0][1]=0;
        E.data[1][1]=1;
        E.data[1][0]=0;
        while(n!=0){
            if((n&1)==1){
                E = mul(E,m);
            }
            m=mul(m,m);
            n>>=1;
        }
        return E;
    }

    //m的m次幂
    public static M mPow(M m,long n,long mod){
        M E = new M();//单位矩阵
        E.data[0][0]=1;
        E.data[0][1]=0;
        E.data[1][1]=1;
        E.data[1][0]=0;
        while(n!=0){
            if((n&1)==1){
                E = mul(E,m,mod);
            }
            m=mul(m,m,mod);
            n>>=1;
        }
        return E;
    }

    public static long fib(long i){
        //[1,1]B^(i-2)
        M A = new M();
        A.data[0][0]=1;
        A.data[0][1]=1;
        A.data[1][0]=0;
        A.data[1][1]=0;
        M B = new M();
        B.data[0][0]=1;
        B.data[0][1]=1;
        B.data[1][0]=1;
        B.data[1][1]=0;
        M ans = mul(A,mPow(B,i-2));
        return ans.data[0][0];
    }

    public static long fib(long i,long mod){
        //[1,1]B^(i-2)
        M A = new M();
        A.data[0][0]=1;
        A.data[0][1]=1;
        A.data[1][0]=0;
        A.data[1][1]=0;
        M B = new M();
        B.data[0][0]=1;
        B.data[0][1]=1;
        B.data[1][0]=1;
        B.data[1][1]=0;
        M ans = mul(A,mPow(B,i-2,mod),mod);
        return ans.data[0][0];
    }

    static void solve(){
        if(m>=n+2){
            System.out.println(fib(n+2,p)-1);
        }else{
            System.out.println((fib(n+2,fib(m))-1)%p);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        n = scanner.nextLong();
        m = scanner.nextLong();
        p = scanner.nextLong();

        solve();

    }

    static class M{
        long data[][] = new long[2][2];
    }

}

方法三

解析

整数快速运算,并在乘法中加入模运算
100分

代码

//如果 m>=n+2那么f(m)>Σf(n),结果是(f(n+2)-1)%p
//否则 结果为(f(n+2)-1)%f(m)%p==f(n+2)%f(m)%p-1
public class _09_斐波那契 {
  public static void main(String[] args) {
    // for (int i = 3; i <=10 ; i++) {
    //   System.out.println(fib(i).longValue());
    // }
    Scanner sc = new Scanner(System.in);
    long n, m, p;
    n = sc.nextLong();
    m = sc.nextLong();
    p = sc.nextLong();
 
    BigInteger bigP = BigInteger.valueOf(p);
 
    if (m >= n + 2) {
      BigInteger ans = fib(n + 2, bigP);
      System.out.println(ans.mod(bigP).longValue() - 1);
    } else {
      BigInteger fibm = fib(m);
      BigInteger ans = fib(n + 2, fibm);
      System.out.println(ans.mod(fibm).mod(bigP).longValue() - 1);
    }
  }
/*快速矩阵求fib*/
  private static BigInteger fib(long m) {
 
    BigInteger[][] ans = mPow(m - 2);
    return ans[0][0].add(ans[1][0]);
  }
  private static BigInteger fib(long m,BigInteger mod) {
 
    BigInteger[][] ans = mPow(m - 2,mod);
    return ans[0][0].add(ans[1][0]);
  }
  /*矩阵快速幂运算*/
  private static BigInteger[][] mPow(long n) {
    // a 1110
    BigInteger[][] a =
        {
            {
                BigInteger.ONE, BigInteger.ONE
            },
            {
                BigInteger.ONE, BigInteger.ZERO
            }
        };
    //单元矩阵
    BigInteger[][] ans =
        {
            {
                BigInteger.ONE, BigInteger.ZERO
            },
            {
                BigInteger.ZERO, BigInteger.ONE
            }
        };
    while (n != 0) {
      if ((n & 1) == 1) {
        //结果ans乘以当前平方
        BigInteger t1=ans[0][0];
        BigInteger t2=ans[1][0];
        ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0]));
        ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1]));
        ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0]));
        ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1]));
      }
      //对a进行平方
      BigInteger t1=a[0][0];
      BigInteger t2=a[1][0];
      BigInteger t3=a[0][1];
      a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0]));
      a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1]));
      a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0]));
      a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1]));
      n >>= 1;
    }
    return ans;
  }
  private static BigInteger[][] mPow(long n,BigInteger mod) {
    BigInteger[][] a =
        {
            {
                BigInteger.ONE, BigInteger.ONE
            },
            {
                BigInteger.ONE, BigInteger.ZERO
            }
        };
    //单元矩阵
    BigInteger[][] ans =
        {
            {
                BigInteger.ONE, BigInteger.ZERO
            },
            {
                BigInteger.ZERO, BigInteger.ONE
            }
        };
    while (n != 0) {
      if ((n & 1) == 1) {
        //结果乘以当前平方
        BigInteger t1=ans[0][0];
        BigInteger t2=ans[1][0];
        ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0])).mod(mod);
        ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1])).mod(mod);
        ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0])).mod(mod);
        ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1])).mod(mod);
      }
      //进行平方
      BigInteger t1=a[0][0];
      BigInteger t2=a[1][0];
      BigInteger t3=a[0][1];
      a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0])).mod(mod);
      a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1])).mod(mod);
      a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0])).mod(mod);
      a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1])).mod(mod);
      n >>= 1;
    }
    return ans;
  }
}
posted @ 2021-03-17 14:28  唐坣  阅读(69)  评论(0)    收藏  举报