【NOI2013T4】矩阵游戏-矩阵优化+十进制快速幂

测试地址:矩阵游戏

做法:观察递推式,很明显可以用矩阵优化,设矩阵C={a b \n 0 1},D={c d \n 0 1},所以F[1][m]=C^(m-1)*{1 \n 1},再推出F[2][1]=D*C^(m-1)*{1 \n 1},数学归纳得F[n][1]=(D*C^(m-1))^(n-1)*{1 \n 1},所以F[n][m]=C^(m-1)*(D*C^(m-1))^(n-1)*{1 \n 1},于是问题就转化为求矩阵快速幂,然而n和m达到10^1000000,所以计算n-1和m-1时要用到一点高精度运算(这个不会...你还来看这个干什么),而且要使用十进制快速幂,即可节省进制转换的时间,复杂度O(lgN)。其实还可以加一点常数优化,注意到计算时2*2矩阵的第二排都是“0 1”,所以我们可以直接省略这个信息,这样矩阵乘法就变成这样一个运算:{a b}*{c d}={a*c a*d+b},优化了常数。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 1000000007
using namespace std;
char sn[1000010],sm[1000010];
long long a,b,c,d;
struct hd {int s[1000010],len;} n,m;
struct mat {long long a,b;} A[1000010],C,ANS;

mat mult(mat A,mat B)
{
  mat S;
  S.a=(A.a*B.a)%mod;
  S.b=((A.a*B.b)%mod+A.b)%mod;
  return S;
}

mat power(hd s)
{
  mat S;
  S.a=1,S.b=0;
  for(int i=s.len-1;i>=0;i--)
  {
    for(int j=1;j<=s.s[i];j++)
	  S=mult(S,A[s.len-i-1]);
  }
  return S;
}

int main()
{
  scanf("%s%s%lld%lld%lld%lld",sn,sm,&a,&b,&c,&d);
  n.len=strlen(sn),m.len=strlen(sm);
  for(int i=0;i<n.len;i++) n.s[i]=sn[i]-'0';
  for(int i=0;i<m.len;i++) m.s[i]=sm[i]-'0';
  n.s[n.len-1]--,m.s[m.len-1]--;
  for(int i=n.len-1;i>=0;i--)
  {
    if (n.s[i]<0)
	{
	  n.s[i]=9;
	  n.s[i-1]--;
	}
	else break;
  }
  for(int i=m.len-1;i>=0;i--)
  {
    if (m.s[i]<0)
	{
	  m.s[i]=9;
	  m.s[i-1]--;
	}
	else break;
  }
  
  A[0].a=a,A[0].b=b;
  for(int i=1;i<=1000001;i++)
  {
    A[i]=A[i-1];
    for(int j=1;j<=9;j++)
	  A[i]=mult(A[i],A[i-1]);
  }
  
  C=power(m);
  A[0].a=c,A[0].b=d;
  A[0]=mult(A[0],C);
  for(int i=1;i<=1000001;i++)
  {
    A[i]=A[i-1];
    for(int j=1;j<=9;j++)
	  A[i]=mult(A[i],A[i-1]);
  }
  ANS=mult(C,power(n));
  
  printf("%lld",(ANS.a+ANS.b)%mod);
  
  return 0;
}


posted @ 2017-03-30 20:00  Maxwei_wzj  阅读(90)  评论(0编辑  收藏  举报