• 【NOI2012T1】随机数生成器-矩阵快速幂+高精度


    测试地址:随机数生成器

    做法:题目都把递推式给出来了,但是n达到了10^18,所以一个一个算肯定爆了,这个时候就要使用矩阵优化,这个递推式弄出状态转移矩阵还是很简单的,这里就不写了。但是还有一个问题,两个10^18数量级的长整数直接乘起来肯定会炸,所以还要写一个高精度......总之各种麻烦,要注意各种细节,一般写错的话都是写这类东西时常犯的错误(比如进位时+=写成=之类的,我会说我也犯错了么),基本上注意了这些东西就可以写出这道题了。

    以下是本人代码(洛谷上能过,BZOJ上WA,不明所以,求解释):

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll unsigned long long
    ll n,m,a,c,g,x;
    struct hd {ll s[41];};
    struct matrix
    {
      hd a[2][2];
    }M[110],N;
    
    void hdfix(hd &a)
    {
      for(int i=1;i<=40;i++)
        if (a.s[i]>=10)
    	{
    	  a.s[i+1]+=a.s[i]/10;
    	  a.s[i]%=10;
    	}
    }
    
    hd change(ll s)
    {
      int i=1;
      hd a;
      memset(a.s,0,sizeof(a.s));
      while(s!=0)
      {
        a.s[i]=s%10;
    	s/=10;
    	i++;
      }
      return a;
    }
    
    hd hdplus(hd a,hd b)
    {
      hd c;
      memset(c.s,0,sizeof(c.s));
      for(int i=1;i<=40;i++)
        c.s[i]=a.s[i]+b.s[i];
      hdfix(c);
      return c;
    }
    
    hd hdmult(hd a,hd b)
    {
      hd c;
      memset(c.s,0,sizeof(c.s));
      for(int i=1;i<=40;i++)
        for(int j=1;j<=40;j++)
    	  c.s[i+j-1]+=a.s[i]*b.s[j];
      hdfix(c);
      return c;
    }
    
    hd hdmod(hd a,ll s)
    {
      ll sum=0;
      for(int i=40;i>=1;i--)
      {
        sum=sum*10+a.s[i];
    	sum%=s;
      }
      return change(sum);
    }
    
    void clear(matrix &A)
    {
      A.a[0][0]=change(0);
      A.a[0][1]=change(0);
      A.a[1][0]=change(0);
      A.a[1][1]=change(0);
    }
    
    matrix matmult(matrix A,matrix B)
    {
      matrix C;
      clear(C);
      for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
    	  for(int k=0;k<=1;k++)
    	    C.a[i][j]=hdmod(hdplus(C.a[i][j],hdmult(A.a[i][k],B.a[k][j])),m);
      return C;
    }
    
    matrix qmult(ll x)
    {
      matrix S;
      clear(S);
      S.a[0][0]=S.a[1][1]=change(1);
      int i=0;
      while(x!=0)
      {
        if (x&1) S=matmult(S,M[i]);
    	x>>=1;i++;
      }
      return S;
    }
    
    void output(hd s)
    {
      bool flag=0;
      for(int i=40;i>=1;i--)
      {
        if (s.s[i]!=0) flag=1;
    	if (flag) printf("%lld",s.s[i]);
      }
    }
    
    int main()
    {
      scanf("%lld%lld%lld%lld%lld%lld",&m,&a,&c,&x,&n,&g);
      clear(M[0]);
      M[0].a[0][0]=change(a);
      M[0].a[0][1]=change(c);
      M[0].a[1][1]=change(1);
      for(int i=1;i<=70;i++)
        M[i]=matmult(M[i-1],M[i-1]);
      clear(N);
      N.a[0][0]=change(x);
      N.a[1][0]=change(1);
      output(hdmod(matmult(qmult(n),N).a[0][0],g));
      
      return 0;
    }
    


  • 相关阅读:
    前端 fetch 通信
    编写高质量的JavaScript代码(一)
    Redis学习笔记1-Redis的介绍和认识
    gitignore不起作用解决的方法
    【我的面经】说说简历的细节——软件开发岗位
    菜鸟的mongoDB学习---(七)MongoDB 备份(mongodump)与恢复(mongorerstore)
    HDU 4927 Series 1
    树状数组求第K小值 (spoj227 Ordering the Soldiers &amp;&amp; hdu2852 KiKi&#39;s K-Number)
    git和SVN的差别
    KVM-Introduce
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793817.html
Copyright © 2020-2023  润新知