• 洛谷P1397 [NOI2013]矩阵游戏


    题意链接

    题意简述

    给定一个二维的递推方程,已知第一项((1,1))求其第((n,m))

    分析

    一道矩阵乘法基础题

    一看到递推式还没有特殊条件就知道是矩阵快速幂

    但是这个(n,m)的范围着实是不正常

    所以考虑到要用个某某定理或者性质把(n,m)的范围缩小

    这里就是费马小定理了

    容易发现,这里的矩阵乘法是满足费马小定理的,但是当(a=1)的情况要特判,(至于为什么详见这篇博客或者这篇博客

    所以接下来我们可以开始构造状态矩阵

    构造状态转移矩阵的方法:若状态矩阵中第 (x) 个数对下一单位时间状态矩阵中第 (y) 个数有影响,则把转移矩阵的第 (x)行第 (y) 列赋值为适当的系数。

    我们发现,状态矩阵中第一个数要乘(a)(b),那么根据上面的定义很容易想到,状态转移矩阵的第一列分别就是 (a)(b),分别对应(f_{(i-1,j)})(1)。我们会发现状态矩阵中第二个值是不变的,它赋值为 (1) 的意义在于能够刚好计算最后的 (+b)

    所以我们可以把单独一行的转移方程写出来:

    (left{ egin{matrix} a & 0\ b & 1 end{matrix} ight})

    那么其实我们每一行转移过后就是行与行之间的转移,那么我们可以把这个转移方程也直接写出来:

    (left{ egin{matrix} c & 0\ d & 1 end{matrix} ight})

    (其实一点变化都没有)

    所以我们手摸一下,可以直接得出:

    我们的初始状态的矩阵要乘上

    [left[ egin{matrix} a & 0\ b & 1 end{matrix} ight]^{(m-1)*n} * left[ egin{matrix} c & 0\ d & 1 end{matrix} ight]^{(n-1)} ]

    最后答案就是初始矩阵的元素(f_{(1,1)})

    那么这道题就结束了

    代码

    代码附上

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const ll MOD=1e9+7,N=1e6+5;
    #define inc(a,b) (a+b>=MOD?a+b-MOD:a+b)
    struct Matrix{
    	ll a[3][3];
    	Matrix(){memset(a,0,sizeof(a));}
    	Matrix operator * (Matrix B){
    		Matrix C;
    		for(int i=1;i<3;i++){
    			for(int j=1;j<3;j++){
    				for(int k=1;k<3;k++){
    					C.a[i][j]=inc(C.a[i][j],a[i][k]*B.a[k][j]%MOD);
    				}
    			}
    		}
    		return C;
    	}
    };
    Matrix QuickPow(Matrix A,ll y){
    	Matrix res;
    	res.a[1][1]=res.a[2][2]=1;
    	while(y){
    		if(y&1) res=res*A;
    		A=A*A;
    		y>>=1;
    	}
    	return res;
    }
    Matrix ans,base,base1;
    string nn,mm;
    ll a,b,c,d,n,m;
    int main(){
    	cin>>nn>>mm>>a>>b>>c>>d;
    	int len1,len2;
    	len1=nn.size(),len2=mm.size(); 
    	for(int i=0;i<len1;i++) n=(n*10+nn[i]-'0')%(a==1?MOD:MOD-1);
    	for(int i=0;i<len2;i++) m=(m*10+mm[i]-'0')%(a==1?MOD:MOD-1);
    	ans.a[1][1]=1,ans.a[1][2]=1;
    	base.a[1][1]=a,base.a[2][1]=b,base.a[2][2]=1;
    	base=QuickPow(base,m-1);
    	base1.a[1][1]=c,base1.a[2][1]=d,base1.a[2][2]=1;
    	base=base*base1;
    	base=QuickPow(base,n-1);
    	base1.a[1][1]=a,base1.a[2][1]=b,base1.a[2][2]=1;
    	base1=QuickPow(base1,m-1);
    	write((ans*(base*base1)).a[1][1]);
    	return 0;
    }
    
    
  • 相关阅读:
    可持久化线段树区间查询 + 永久化标记 T^T online judge 2507
    可持久化线段树
    T^T online judge 3441
    食物链
    T^T ONLINE JUDGE 2592
    HDU 6312 GAME
    HDU 1430 魔板
    栈的操作链表+数组版
    Codeforces Round #468 (Div. 2, based on Technocup 2018 Final Round) D. Peculiar apple-tree
    Codeforces Round #468 (Div. 2, based on Technocup 2018 Final Round) C. Laboratory Work
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14092930.html
Copyright © 2020-2023  润新知