1. 程式人生 > >bzoj 3240: [Noi2013]矩陣遊戲

bzoj 3240: [Noi2013]矩陣遊戲

struct cpp 滿足 inline noi char s esp 只需要 sin

Description

婷婷是個喜歡矩陣的小朋友,有一天她想用電腦生成一個巨大的n行m列的矩陣(你不用擔心她如何存儲)。她生成的這個矩陣滿足一個神奇的性質:若用F[i][j]來表示矩陣中第i行第j列的元素,則F[i][j]滿足下面的遞推式:

F[1][1]=1
F[i,j]=aF[i][j-1]+b (j!=1)
F[i,1]=c
F[i-1][m]+d (i!=1)
遞推式中a,b,c,d都是給定的常數。

現在婷婷想知道F[n][m]的值是多少,請你幫助她。由於最終結果可能很大,你只需要輸出F[n][m]除以1,000,000,007的余數。

Solution

這題可以暴力矩乘跑過去
設初始矩陣為 \(A\)

,列轉移矩陣為 \(B\),行轉移矩陣為 \(C\)
那麽答案就是 \(A*(B^{m-2}*C)^{n-2}*B\)

矩乘要用十進制快速冪,和二進制差不多,這一位是多少就乘多少次就行了

#include<bits/stdc++.h>
using namespace std;
#define RG register
const int mod=1e9+7;
struct mat{
    int a[2][2];
    mat(){memset(a,0,sizeof(a));}
    inline mat operator *(const mat &p){
        mat ret;
        for(RG int i=0;i<2;i++)
            for(RG int j=0;j<2;j++)
                for(RG int k=0;k<2;k++)
                    ret.a[i][j]=(ret.a[i][j]+1ll*a[i][k]*p.a[k][j])%mod;
        return ret;
    }
};
const int N=1e6+10;
char s1[N],s2[N];
inline void ksm(mat &S,mat T,int k){
    while(k){
        if(k&1)S=S*T;
        T=T*T;k>>=1;
    }
}
inline mat mul(mat S,mat T,char *s,int len){
    for(RG int i=len;i>=1;i--){
        ksm(S,T,s[i]-48);
        if(i>1)ksm(T,T,9);
    }
    return S;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%s%s",s2+1,s1+1);
  int a,b,c,d,len;
  cin>>a>>b>>c>>d;
  if(strlen(s1+1)==1 && s1[1]=='1' && strlen(s2+1)==1 && s2[1]=='1')
      puts("1"),exit(0);
  
  mat S,T,O,R;
  if(strlen(s1+1)==1 && s1[1]=='1'){
      S.a[0][0]=S.a[0][1]=1;S.a[1][0]=S.a[1][1]=0;
      T.a[0][0]=c;T.a[1][0]=d;T.a[1][1]=1;
      len=strlen(s2+1);s2[len]--;
      for(int i=len;i>=1;i--)if(s2[i]<'0')s2[i]+=10,s2[i-1]--;else break;
      S=mul(S,T,s2,len);
      cout<<S.a[0][0]<<endl;
      return 0;
  }
  if(strlen(s2+1)==1 && s2[1]=='1'){
      S.a[0][0]=S.a[0][1]=1;S.a[1][0]=S.a[1][1]=0;
      T.a[0][0]=a;T.a[1][0]=b;T.a[1][1]=1;
      len=strlen(s1+1);s1[len]--;
      for(int i=len;i>=1;i--)if(s1[i]<'0')s1[i]+=10,s1[i-1]--;else break;
      S=mul(S,T,s1,len);
      cout<<S.a[0][0]<<endl;
      return 0;
  }
  S.a[0][0]=a;S.a[1][0]=b;S.a[1][1]=1;
  T.a[0][0]=c;T.a[1][0]=d;T.a[1][1]=1;T.a[0][1]=0;
  
  len=strlen(s1+1);s1[len]-=2;
  for(int i=len;i>=1;i--)if(s1[i]<'0')s1[i]+=10,s1[i-1]--;else break;
  S=mul(S,S,s1,len);O=S;S=S*T;

  len=strlen(s2+1);s2[len]-=2;
  for(int i=len;i>=1;i--)if(s2[i]<'0')s2[i]+=10,s2[i-1]--;else break;
  S=mul(S,S,s2,len);

  T.a[0][0]=T.a[0][1]=1;T.a[1][0]=T.a[1][1]=0;
  S=T*S;S=S*O;
  cout<<S.a[0][0]<<endl;
  return 0;
}

bzoj 3240: [Noi2013]矩陣遊戲