您的位置:首页 > 其它

[BZOJ 2875 & Vijos 1725] NOI 2012 随机数生成器 · 矩阵乘法+快速乘法

2015-03-27 13:08 429 查看
矩阵乘法+快速乘法

话说这种NOIP的题能出现在NOI里吓谁呢。。。

x0=x

x1=a*x0+c=a*x+c

x2=a*x1+c=a^2*x+a*c+c

x3=a*x2+c=a^3*x+a^2*c+a*c+c

依次类推可以得到:xn=a^n*x+a^(n-1)*c+a^(n-2)*c+.....+a*c+c

一开始笔者自己写了个矩阵结果挂掉了。。。然后看了一下CCF的题解觉得这个矩阵好巧妙,看来还是需要多加练习啊!

matrix=

,我们把xn的式子分成要a^n*x和后面的常数部分,那么我们将matrix自乘n次以后,matrix[1][1]就是a^n,matrxi[1][2]就是后面的常数部分,所以最后的结果就是(x0*matrix[1][1]+matrix[1][2])%m%g。

另外如果直接相乘的话会爆long long,所以要用到一个叫做快速乘法的东西,说白了其实就是个类似快速幂的东西。小学大家都学过,x*y的意义就是y个x相加,剩下的就一目了然啦~(代码line17~24)

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
#define ll long long 

const int n=2;
ll a,b,mod,g,k,x0,xn;
struct matrix{
	ll num[3][3];
	void init(){
		memset(num,0,sizeof num);
	}
}ans,unit;

ll mult(ll x,ll y){
	ll p=0;
	for (;y;y>>=1){
		if (y&1) p=(p+x)%mod;
		x=(x+x)%mod;
	}
	return p;
}

matrix operator *(matrix a,matrix b){
	matrix c;
	c.init();
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)	
			for (int t=1;t<=n;t++)
				c.num[i][j]=(c.num[i][j]+mult(a.num[i][t],b.num[t][j]))%mod;
	return c;
}

int main(){
	cin>>mod>>a>>b>>x0>>k>>g;
	unit.num[1][1]=a;unit.num[1][2]=b;unit.num[2][2]=1;
	ans.num[1][1]=ans.num[2][2]=1;
	
	for (;k;k>>=1){
		if (k&1) ans=ans*unit;
		unit=unit*unit;
	}
	
	xn=(mult(ans.num[1][1],x0)+ans.num[1][2])%mod;
	cout<<xn%g<<endl;
	return 0;
}
总结:矩阵里面的所有值并不一定都是我们最终结果想要的,如本题矩阵中的matrix第二行,但是用上这些东西可以帮我们更好的得出最终结果,所以说矩阵乘法写起来虽然简单,但是每一题的矩阵都不尽相同,各有妙处,推出矩阵才是最核心也是最巧妙的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: