zoukankan      html  css  js  c++  java
  • hdu 1757 (矩阵快速幂) 一个简单的问题 一个简单的开始

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1757

    题意不难理解,当x小于10的时候,数列f(x)=x,当x大于等于10的时候f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10); 

    所求的是f(x)取m的模,而x,m,a[0]至a[9]都是输入项

    初拿到这道题,最开始想的一般是暴力枚举,通过for循环求出f(x)然后再取模,但是有两个问题,首先f(x)可能特别大,其次是枚举超时。

    所以,想到可以用到通过构造矩阵快速幂的方法。

    稍微有点线性代数基础的人(比如本人)都知道可以构造一个10*10的矩阵

    (10有点大,这里以3*3的代替,题意还是不变)

                       0  0  a0                                                0  0  a0    0  0  a0 

    (f0,f1,f2)*   1  0  a1 --->(f1,f2,f3)     然后(f0,f1,f2)* 1  0  a1 * 1  0  a1 --->(f2,f3,f4)

                       0  1  a2                                                0  1  a2    0  1  a2

                                           0  0  a0   0  0  a0

    最后一直到f(x)   (f0,f1,f2)* 1  0  a1* 1  0  a1*******--->(fx-2,fx-1,fx)

                                           0  1  a2   0  1  a2

    10*10的矩阵也基本很这个一样,然后光有矩阵并没有太大的卵用,还得用快速幂来取模,只不过换成了矩阵而已。

    先开两个二维数组把矩阵给存起来(对,开两个存一模一样的矩阵,如果一下子没有反应过来为什么的等你写到这里的时候就知道为什么了)

    然后第三个数组存相乘过程中的结果。(如果快速幂不会的请百度)

    最后的用已知的f(i)数组的前十项分别乘以最终矩阵的最后一列的和就是最终结果

    (PS:加减乘法的取模可以分步,而除法不行)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 long long jz1[11][11],jz2[11][11],jz3[11][11],i,j,k;
     6 long long a[11],m;
     7 long long lsy(long long n)
     8 {
     9     long long sum=0;
    10     for (i=0;i<=9;i++){  //创建矩阵
    11         for (j=0;j<=9;j++){
    12             if (j!=9){
    13                 if (i-j==1)
    14                 {
    15                     jz1[i][j]=1;
    16                     jz2[i][j]=1;
    17                 }
    18                 else
    19                 {
    20                     jz1[i][j]=0;
    21                     jz2[i][j]=0;
    22                 }
    23             }
    24             else
    25             {
    26                 jz1[i][9]=a[9-i];
    27                 jz2[i][9]=a[9-i];
    28             }
    29         }
    30     }
    31     n-=10;
    32     while (n!=0)  //快速幂取模
    33     {
    34         if (n&1)
    35         {
    36             memset(jz3,0,sizeof(jz3));
    37             for (i=0;i<=9;i++){
    38                 for (j=0;j<=9;j++){
    39                     for (k=0;k<=9;k++){
    40                         jz3[i][j]+=jz1[i][k]*jz2[k][j]%m;
    41                     }
    42                 }
    43             }
    44             memcpy(jz2,jz3,sizeof(jz3));
    45         }
    46         memset(jz3,0,sizeof(jz3));
    47             for (i=0;i<=9;i++){
    48                 for (j=0;j<=9;j++){
    49                     for (k=0;k<=9;k++){
    50                         jz3[i][j]+=jz1[i][k]*jz1[k][j]%m;
    51                     }
    52                 }
    53             }
    54             memcpy(jz1,jz3,sizeof(jz3));
    55             n>>=1;  //不要忘了
    56     }
    57     for (i=0;i<10;i++) //求出f(x)
    58          sum=(((i%m)*jz2[i][9])%m+sum)%m;
    59     return sum;
    60 }
    61 int main()
    62 {
    63     long long n;
    64     while (~scanf("%I64d %I64d",&n,&m))
    65     {
    66         if (n==0&&m==0) break;
    67         for (i=0;i<=9;i++)
    68             scanf("%l64d",&a[i]);
    69         if (n>=10)
    70             printf("%I64d
    ",lsy(n));
    71         else
    72             printf("%I64d
    ",n%m);
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    Spring Boot Logback 默认配置
    CAS 之 Https And Database Authentication(三)
    CAS 之 Hello World(二)
    CAS 之 Apereo CAS 简介(一)
    对 url 中含有的中文进行转码操作
    Python Hello World
    集合与数组简明介绍
    Javascript中使用WScript.Shell对象执行.bat文件和cmd命令
    WOL远程开机
    Windows Server 2016-Windows安全日志ID汇总
  • 原文地址:https://www.cnblogs.com/JJCHEHEDA/p/4662227.html
Copyright © 2011-2022 走看看