zoukankan      html  css  js  c++  java
  • codevs4247 奇特的生物

    4247 奇特的生物

    题目描述 Description

    科学家们最近发现了一种奇怪的生物,它们每天长大一岁,刚出生的宝宝为1岁,且它们的年龄没有上限。已知年龄为1 岁,2岁,3岁,……,k岁的个体具有生育能力,当年龄为i的具有生育能力的个体将长大一岁时会生下ai个1岁的幼崽。假设第一天只有一个年龄为1的幼 崽,现在科学家们想知道第x天年龄为y的个体有多少,但由于该物种增长速度太快,于是他们将这个任务交给了你。由于这个数可能很大,你需要对p取模。

     

    输入描述 Input Description

    输入数据第一行给定四个整数k,x,y,p。

    第二行包括k个整数,第i个整数代表ai。

     

    输出描述 Output Description

    输出数据包含一行,表示第x天年龄为y的个体的数量对p取模后的结果。

     

    样例输入 Sample Input

    【样例输入 1】

    3 3 1 1007

    1 1 1

    【样例输入 2】

    3 6 2 1007

    1 2 1

     

    样例输出 Sample Output

    【样例输出1】

    2

    【样例输出 2】

    13

     

    数据范围及提示 Data Size & Hint

     

    【思路】

      矩阵乘法。

      可以总结出题目所述的转换规则如下:

       |F1,F2,F3…Fk| => |a1*F1+a2*F2+…ak*Fk , F1,F2,…Fk-1|

      原矩阵A:

       |1,0,0,…0|

      转换矩阵T:

       |a1,1,0,0…|

       |a2,0,1,0…|

       |.. , ..,..1…|

       |ak,0,0 0…|

     分类讨论(标号从0开始):

      如果y>x 转移不到数目为0

      否则

         如果y<=k A=A*(T^(x-1))输出A[0][y-1]

         否则

            A=A*(T^(x-y+k)) 输出A[0][k-1]

            (注意到只要是年龄比k大数目就不会发生变化,所以只要把y所对应的计算到k-1即可)

      又:其实只要是1岁以后数目都不会发生变化,上述麻烦了。

    【代码】

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 typedef long long LL;
     6 const int maxn = 30+5;
     7 LL k,x,y,m;
     8 LL a[maxn];
     9 
    10 LL multi( LL y , LL cnt ) {
    11     if ( ! cnt ) return 0 ;
    12     if ( cnt == 1 ) return y % m ;
    13     LL rec = multi( y , cnt / 2 ) ;
    14     rec = ( rec + rec ) % m ;
    15     if ( cnt % 2 ) rec = ( rec + y ) % m ;
    16     return rec ;
    17 }
    18 struct Matrix{
    19     int r,c;
    20     LL N[maxn][maxn];
    21     void init(int r,int c) {
    22         this->r=r, this->c=c;
    23         memset(N,0,sizeof(N));
    24     }
    25     Matrix operator*(Matrix& B)const{
    26         Matrix C;
    27         C.init(r,B.c);
    28         for(int i=0;i<C.r;i++)
    29            for(int j=0;j<C.c;j++)
    30            {
    31               for(int k=0;k<c;k++) C.N[i][j] += multi(N[i][k],B.N[k][j]);
    32               C.N[i][j]%=m;
    33           }
    34         return C;
    35     }
    36     Matrix pow(LL p) {
    37         Matrix tmp=*this;
    38         Matrix ans;
    39         ans.init(r,r);
    40         for(int i=0;i<r;i++) ans.N[i][i]=1;
    41         while(p) {
    42             if(p&1) ans=ans*tmp;
    43             tmp=tmp*tmp;
    44             p>>=1;
    45         }
    46         return ans;
    47     }
    48 }A,T;
    49 
    50 int main() {
    51     scanf("%lld%lld%lld%lld",&k,&x,&y,&m);
    52     for(int i=0;i<k;i++) scanf("%lld",&a[i]);
    53     if(y>x) {
    54         printf("0");
    55         return 0;
    56     }
    57     A.init(1,k);
    58     A.N[0][0]=1;
    59     T.init(k,k);
    60     for(int i=0;i<k;i++) T.N[i][0]=a[i];
    61     for(int i=1;i<k;i++) T.N[i-1][i]=1;
    62     if(y<=k)
    63     {
    64         T=T.pow(x-1);
    65         A=A*T;
    66         printf("%lld ",A.N[0][y-1]);
    67     }else {
    68         x=x-y+k;
    69         T=T.pow(x-1);
    70         A=A*T;
    71         printf("%lld",A.N[0][k-1]);
    72     }
    73     return 0;
    74 }
  • 相关阅读:
    自学Linux Shell14.3-创建临时文件
    自学Linux Shell14.2-在脚本中使用其他文件描述符
    自学Linux Shell14.1-理解输入输出
    自学Linux Shell13.3-获得用户输入(read命令)
    自学Linux Shell13.2-选项处理(主要getopt、getopts命令)
    自学Linux Shell13.1-命令行参数
    自学Linux Shell12.8-循环实例
    自学Linux Shell12.7-控制循环break、continue命令
    自学Linux Shell12.6-嵌套循环for命令
    自学Linux Shell12.5-while、until命令
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4932057.html
Copyright © 2011-2022 走看看