矩阵乘法+快速乘法
话说这种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第二行,但是用上这些东西可以帮我们更好的得出最终结果,所以说矩阵乘法写起来虽然简单,但是每一题的矩阵都不尽相同,各有妙处,推出矩阵才是最核心也是最巧妙的。