• bzoj 3240: [Noi2013]矩阵游戏


    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;
    }
    
    
  • 相关阅读:
    Binary Tree Maximum Path Sum
    ZigZag Conversion
    Longest Common Prefix
    Reverse Linked List II
    Populating Next Right Pointers in Each Node
    Populating Next Right Pointers in Each Node II
    Rotate List
    Path Sum II
    [Leetcode]-- Gray Code
    Subsets II
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8563970.html
Copyright © 2020-2023  润新知