• 矩阵快速幂 从入门到入门


    1.luogu P3216 [HNOI2011]数学作业

    前言:

    这sb题我竟然写了一下午,我TCL。
    细节有点多,再加上我对矩阵快速幂的板子不熟,调了很长时间。

    解析:

    首先可以发现一个事情,不考虑进位的话,每次在末尾加一个数,相当于原数乘(10^k)再加上(i) ;
    转移矩阵如下:(因为我Markdown太菜了不会打矩阵,就用这位大佬的题解里面的图了)

    显然可以矩阵快速幂,因为每次的初始矩阵不一样,只要分段求就行了。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    const int maxn=100000+10,N=3;
    #define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
    #define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
    char buf[1 << 20], *p1, *p2;
    ll ans,n,mod;
    struct Matrix{
    	ll c[5][5];
    }A;
    ll mul(ll x,ll y){
    	ll res=0;
    	ll base=x;
    	while(y){
    		if(y&1) res=(res+base)%mod;
    		base=(base+base)%mod;
    		y>>=1;
    	}
    	return res;
    }
    Matrix operator *(const Matrix &x,const Matrix &y){
    	Matrix a;
    	memset(a.c,0,sizeof(a.c));
    	for(int i=1;i<=N;++i){
    		for(int j=1;j<=N;++j){
    			for(int k=1;k<=N;++k){
    				a.c[i][j]=(a.c[i][j]+mul(x.c[i][k],y.c[k][j]))%mod;
    			}
    		}
    	}
    	return a;
    }
    ll qpow(ll x,ll y){
    	ll res=1;
    	ll base=x;
    	while(y){
    		if(y&1) res=mul(res,base);
    		base=mul(base,base);
    		y>>=1;
    	}
    	return res;
    }
    void clear(Matrix &s,int l){
    	memset(s.c,0,sizeof(s.c));
    	s.c[1][1]=qpow(1ll*10,l);
    	s.c[1][2]=s.c[2][2]=s.c[2][3]=s.c[3][3]=1;
    }
    Matrix qp(ll x){
    	Matrix s;
    	memset(s.c,0,sizeof(s.c));
    	for(int i=1;i<=N;++i) s.c[i][i]=1;
    	while(x){
    		if(x&1) s=A*s;
    		A=A*A;
    		x>>=1;
    	}
    	return s;
    }
    void Solve1(){
    	ans= n ? 1 : 0 ;
    	for(int i=2;i<=n;++i) ans=ans*10+i;
    	printf("%llu",ans%mod);
    }
    void Solve(){
    	scanf("%lld%lld",&n,&mod);
    	if(n<10){
    		Solve1();
    		return;
    	}
    	ans=123456789%mod;
    	ll now=99,len=2,last=10;
    	while(now<n){
    		clear(A,len);
    		Matrix ccc=qp(now-last);
    		ans=(mul(ans,qpow(10,len))+last)%mod;
    		ans=(mul(ccc.c[1][1],ans)+mul(ccc.c[1][2],(last+1))+ccc.c[1][3])%mod;
    		last=now+1;
    		now=now*10+9;
    		len++;
    	}
    	clear(A,len);
    	Matrix ccc=qp(n-last);
    	ans=(mul(ans,qpow(10,len))+last)%mod;
    	ans=(mul(ccc.c[1][1],ans)+mul(ccc.c[1][2],(last+1))+ccc.c[1][3])%mod;
    	printf("%llu",ans);
    }
    int main(){
    	freopen("le.in","r",stdin);
    	freopen("le.out","w",stdout);
    	Solve();
    	return 0;
    }
    
    

    2.luogu P1349 广义斐波那契数列

    前言:

    第一次接触矩阵快速幂,应该就是fibonacci数列了吧。
    然而我还是调了好长时间,WTCL

    解析:

    转移矩阵:

    没啥可说的,调了半小时发现自己初始矩阵写错了。。。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int n=2,maxn=4;
    ll k,a1,a2,mod,p,q;
    struct Matrix{
    	ll c[maxn][maxn];
    }A;
    Matrix operator*(const Matrix &x,const Matrix &y){
    	Matrix a;
    	memset(a.c,0,sizeof(a.c));
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=n;++j){
    			for(int k=1;k<=n;++k){
    				a.c[i][j]=(a.c[i][j]+x.c[i][k]*y.c[k][j]%mod)%mod;
    			}
    		}
    	}
    	return a;
    }
    Matrix qpow(){
    	Matrix s;
    	memset(s.c,0,sizeof(s.c));
    	for(int i=1;i<=n;++i) s.c[i][i]=1;
    	while(k){
    		if(k&1) s=s*A;
    		A=A*A;
    		k>>=1;
    	}
    	return s;
    }
    void Solve(){
    	scanf("%lld%lld%lld%lld%lld%lld",&p,&q,&a1,&a2,&k,&mod);
    	if(k==1) {
    		printf("%lld
    ",a1);
    		return;
    	}
    	if(k==2){
    		printf("%lld
    ",a2);
    		return;
    	}
    	k-=2;
    	memset(A.c,0,sizeof(A.c));
    	A.c[1][1]=p;
    	A.c[1][2]=q;
    	A.c[2][1]=1;
    	Matrix ans=qpow();
    	printf("%lld
    ",(ans.c[1][1]*a2%mod+ans.c[1][2]*a1%mod)%mod);
    }
    int main(){
    //	freopen("in","r",stdin);
    //	freopen("out","w",stdout);
    	Solve();
    	return 0;
    }
    
    
  • 相关阅读:
    Shell 中引用符号的名称及意义
    查看该目录下有几个文件夹几个文件的shell代码
    Linux下find 命令用法详解+实例
    Linux中echo的用法
    man help
    《鸟哥的linux私房菜》关于数据流重导向
    linux开机自动加载服务设置
    Shell调试技术总结(二)
    Shell中关于if,case,for,while等的总结
    硬盘的分区
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13886147.html
Copyright © 2020-2023  润新知