05
1.矩阵快速幂
https://www.luogu.com.cn/problem/P3390
就是矩阵乘法+快速幂,本来想用宏定义定义mod,结果不知道为什么会出错,改成const就过了
//#include<iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const ll max_n=1e5+1000; const ll inf=0x3f3f3f3f; ll n,m,a[120][120]; struct mat{ int len; ll m[110][110]; mat times(mat b){ mat c; c.len=len; for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ ll res=0; for(int v=0;v<len;v++){ res+=m[i][v]*b.m[v][j]%mod; }c.m[i][j]=(res+mod)%mod; } } return c; } void output(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ cout<<m[i][j]<<' '; }cout<<endl; } } void uni(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ if(i==j) m[i][j]=1; else m[i][j]=0; } } } }; mat qmp(mat a,ll k){ mat res,x; res.len=a.len; x.len=a.len; res.uni(),x=a; while(k){ if(k&1){ res=res.times(x); }x=x.times(x); k>>=1; } return res; } int main(){ //freopen("in.txt","r",stdin); ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>m; mat a; a.len=n; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ cin>>a.m[i][j]; } } qmp(a,m).output(); return 0; }
2.矩阵加速
https://www.luogu.com.cn/problem/P1939
板子题,矩阵长这样:
然后就是套上快速幂求就可以了,结果就是第一行的和
//#include<iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const ll max_n=1e5+1000; const ll inf=0x3f3f3f3f; ll n,m,a[120][120]; struct mat{ int len; ll m[110][110]; mat times(mat b){ mat c; c.len=len; for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ ll res=0; for(int v=0;v<len;v++){ res+=m[i][v]*b.m[v][j]%mod; }c.m[i][j]=(res+mod)%mod; } } return c; } void output(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ cout<<m[i][j]<<' '; }cout<<endl; } } void uni(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ if(i==j) m[i][j]=1; else m[i][j]=0; } } } }; mat qmp(mat a,ll k){ mat res,x; res.len=a.len; x.len=a.len; res.uni(),x=a; while(k){ if(k&1){ res=res.times(x); }x=x.times(x); k>>=1; } return res; } int main(){ //freopen("in.txt","r",stdin); ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; mat a,ans; a.len=3; a.m[0][0]=1,a.m[0][1]=0,a.m[0][2]=1; a.m[1][0]=1,a.m[1][1]=0,a.m[1][2]=0; a.m[2][0]=0,a.m[2][1]=1,a.m[2][2]=0; while(n--){ cin>>m; if(m<=3){ cout<<1<<endl; continue; }else{ ans=qmp(a,m-3); ll res=(ans.m[0][0]+ans.m[0][1]+ans.m[0][2])%mod; cout<<res<<endl; } } return 0; }
3.斐波那契公约数
https://www.luogu.com.cn/problem/P1306
事实证明,打表乃找规律第一要义,打出来前20x20个结果,发现结果总就那么几个值,又发现这些值全是本身数列里的元素,结果就可以得到以下规律:
然后就简单了,同上。
//#include<iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e8; const ll max_n=1e5+1000; const ll inf=0x3f3f3f3f; ll n,m,a[120][120]; struct mat{ int len; ll m[110][110]; mat times(mat b){ mat c; c.len=len; for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ ll res=0; for(int v=0;v<len;v++){ res+=m[i][v]*b.m[v][j]%mod; }c.m[i][j]=(res+mod)%mod; } } return c; } void output(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ cout<<m[i][j]<<' '; }cout<<endl; } } void uni(){ for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ if(i==j) m[i][j]=1; else m[i][j]=0; } } } }; mat qmp(mat a,ll k){ mat res,x; res.len=a.len; x.len=a.len; res.uni(),x=a; while(k){ if(k&1){ res=res.times(x); }x=x.times(x); k>>=1; } return res; } ll gcd(ll a,ll b){ if(b==0){ return a; }else return gcd(b,a%b); } int main(){ //freopen("in.txt","r",stdin); ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>m; mat a,ans; a.len=2; a.m[0][0]=1,a.m[0][1]=1; a.m[1][0]=1,a.m[1][1]=0; n=gcd(n,m); if(n<=2){ cout<<1<<endl; }else{ ans=qmp(a,n-2); cout<<(ans.m[0][0]+ans.m[0][1])%mod<<endl; } return 0; }