返回顶部

矩阵乘法

Update2024.7.30

P2044 [NOI2012] 随机数生成器
唐题,但是需要龟速乘法

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
ll g,a,c,x0,n,mod;
ll mul(ll a,ll b)
{
	ll ans=0;
	while(b)
	{
		if(b&1)ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1ll;
	}
	return ans;
}
struct Matrix
{
	ll n,m,a[5][5];
	Matrix(int n,int m):n(n),m(m){memset(a,0,sizeof a);}
	Matrix operator * (const Matrix& A)const
	{
		Matrix ans(2,2);
		for(int i=1;i<=2;i++)
			for(int j=1;j<=2;j++)
				for(int k=1;k<=2;k++)
					ans.a[i][j]=(ans.a[i][j]+mul(a[i][k],A.a[k][j])%mod)%mod;
		return ans;
	}
};
Matrix qpow(Matrix ans,Matrix a,ll b)
{
	while(b)
	{
		if(b&1)ans=a*ans;
		b>>=1ll;
		a=a*a;
	}
	return ans;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	Matrix G(2,2);
	Matrix b(2,1);
	cin>>mod>>a>>c>>x0>>n>>g;
	G.a[1][1]=a;G.a[1][2]=c;G.a[2][2]=1;
	b.a[1][1]=x0%mod;
	b.a[2][1]=1;
	// cout<<"*********"<<endl;
	b=qpow(b,G,n);
	cout<<b.a[1][1]%g<<endl;
	return 0;
}

PAST

佳佳的 Fibonacci
由题可知,我们需要用矩阵乘法求出\(T(n)\)
现在就考虑构造几位维的矩阵,我么知道\(F_n=F_{n-1}+F_{n-2}\)
所以求出\(F_n\)至少需要两个元素,然后\(T_n\)呢,就需要\(nF_{n-1}+nF_{n-2}+T_{n-1}\)

\[\left[ \begin{matrix} T_{n-1} & nF_{n-1} & nF_{n-2} & F_{n-1} & F_{n-2} \\ 1 & 0 & 0 & 0 & 0\\ 1 & 1 & 1 & 0 & 0\\ 1 & 1 & 0 & 0 & 0\\ 0 & 1 & 1 & 1 & 1\\ 0 & 1 & 0 & 1 & 0\\ \end{matrix} \right] \]

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10;
ll mod,n;
inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
inline void write(ll x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
struct Mat
{
	ll n,m;
	ll a[N][N];
	void zero()
	{
		memset(a,0,sizeof(a));
	}
	void one() { 
		zero();
		for (int i = 1; i <= n; i++) a[i][i] = 1;
	}
	void resize(int x, int y) { 
		n = x; m = y;
	}
	Mat operator *(const Mat &A)const
	{
		Mat res;
		res.resize(n,A.m);
		res.zero();
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=A.m;j++)
			{
				for(int k=1;k<=m;k++)
				{
					res.a[i][j]=((long long)res.a[i][j]+(ll)a[i][k]*A.a[k][j])%mod;
				}		
			}
		}
		return res;
	}
}mat;
Mat qpow(Mat A, ll b) {
	if(b==-1)
	{
		cout<<1;
		exit(0);
	}
	Mat res;
	res.resize(5, 5);
//	res.one();
	res.a[1][1]=3;
    res.a[1][2]=3;
    res.a[1][3]=3;
    res.a[1][4]=1;
    res.a[1][5]=1;
	while (b) {
	if (b & 1) {
	res = res * A;
	}
	A = A * A;
	b >>= 1;
	}
	return res;
}
int main()
{
//	n=read(),mod=read();
	scanf("%d%d",&n,&mod);
//	Mat mat;
	mat.resize(5,5);
	mat.a[1][1]=mat.a[2][1]=mat.a[2][2]=mat.a[2][3]=mat.a[3][1]=mat.a[3][2]=1;
	mat.a[4][4]=mat.a[4][5]=mat.a[5][4]=mat.a[4][2]=mat.a[4][3]=mat.a[5][2]=1;
	mat.a[3][3]=0;
	mat=qpow(mat,n-2);
//	write(mat.a[1][1]);
//	for (int i = 1; i <= 5; i++)cout<<mat.a[i][i]<<" ";
	printf("%lld ",mat.a[1][1]%mod);
	return 0;
}

迷路
\(f_t[i,j]\)表示从i点到j点花费时间为t的方案数
我们假设边权只有1

\[\sum_{k=1}^nf_1[i,k]*f_{t-1}[k,j] \]

f1就是最初的矩阵啊。
我们1个点建9个小点,只有第1小点可以跨越小点的集合。
那么我们建立第i+1小点到第i小点的w=1的单向边
而要连的两个点1到点2则将小点集合1中的小点1和集合2中的小点w相连。
如下图(只画出了点1到点2经过的路径)
image
image

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100;
int mod=2009,n,t;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
}
struct mat
{
	int n,m;
	int a[N][N];
	mat()
	{
		memset(a,0,sizeof(a));
	}
	void clear()
	{
		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++)a[i][i]=1;
	}
	void resize(int x,int y)
	{
		n=x,m=y;
	}
	mat operator *(const mat &A)const
	{
		mat res;
		res.resize(n,A.n);
//		res.n=A.n;
//		res.c();
//		res.clear();
//		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=A.m;j++)
			{
				for(int k=1;k<=m;k++)
				{
					res.a[i][j]=(res.a[i][j]+(ll)a[i][k]*A.a[k][j])%mod;
				}	
			}		
		}
		return res; 
	}	
};
mat qpow(mat A,int q)
{
	mat res;
	res.resize(9*n,9*n);
//	res.n=A.n;
	res.clear();
	while(q)
	{
		if(q&1)res=res*A;
		A=A*A;
//		q>>=1;
		q/=2;
	}
	return res; 
}

int main()
{
//	n=read(),t=read();
	cin>>n>>t;
	mat rm;
	rm.resize(9*n,9*n);
//	rm.clear();
	int b;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=8;j++)
		{
			rm.a[(i-1)*9+j][(i-1)*9+j+1]=1;
		}
		for(int j=1;j<=n;j++)
		{
			scanf("%1d",&b);
			if(b)
			{
				rm.a[(i-1)*9+b][(j-1)*9+1]=1;
			}
		}
	}
	rm=qpow(rm,t);
	printf("%d",rm.a[1][9*n-8]);
	return 0;
}
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod=2009;
struct Mat
{
	int n,m;
	int a[101][101];
	void zero()
	{
		memset(a,0,sizeof(a));
	}
	void one()
	{
		zero();
		for(int i=1;i<=n;i++)a[i][i]=1;
	}
	void resize(int x,int y)
	{
		n=x;m=y;
	}
	Mat operator *(const Mat &A)const
	{
		Mat res;
		res.resize(n,A.m);
		res.zero();
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=A.m;j++)
			{
				for(int k=1;k<=m;k++)
				{
					res.a[i][j]=(res.a[i][j]+(ll)a[i][k]*A.a[k][j])%mod;
				}
			}
		}
		return res;
	}
	void out()
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
				cout<<a[i][j]<<" ";		
			cout<<endl;
		}

	}
};
ll n;
Mat qpow(Mat A,ll b)
{
	Mat res;
	res.resize(9*n,9*n);
	res.one();
	while(b)
	{
		if(b&1)res=res*A;
		b>>=1;
		A=A*A;
	}
	return res;
}
int pos(int u,int v)
{
	return u+n*v;
}
int main()
{
	int T;
//	ios_base::sync_with_stdio(false);
//	cin.tie(0);cout.tie(0);
	cin>>n>>T;
	Mat res;
	int x;
	res.resize(9*n,9*n);
	res.zero();
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= 8; ++j)
			res.a[pos(i, j)][pos(i, j - 1)] = 1; 
		for (int j = 1; j <= n; ++j)
		{
			scanf("%1d", &x); 
			if (x)
 				res.a[i][pos(j, x - 1)] = 1; 
		}
	}
	res=qpow(res,T);
	cout<<res.a[1][n];
	return 0;
}
posted @ 2024-03-30 20:04  wlesq  阅读(12)  评论(1编辑  收藏  举报