zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    流 例题

    容器集合整理
    容器集合
    容器 集合知识点
    面向对象回顾
    面向对象例题
    Java常用的8大排序算法
    Java中两个动态代理
    为什么synchronized无法禁止指令重排,却能保证有序性
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8563970.html
Copyright © 2011-2022 走看看