[题解]NOI2012 随机数据生成器
题目描述
\(X_i=(aX_{i-1}+c)mod M\)
给出\(X_0,a,c,M,G,n\),求\(X_n\)%\(G\)
分析
我怎么会说自己一上来就打逆元然后直接GG呢
先把式子化成\(a^n*X_0\)+一个等比数列\(*C\)
随便一波发现可以用矩乘,然后直接矩乘杀进去(数学老师附体)
或者可以递推,每一次都可以把等比数列拆成两半,复杂度是log的
代码
#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
using namespace std;
LL MOD,ra,c,Xl,n,G;
LL MSC(LL x,LL y){
LL res=0;
x%=MOD;y%=MOD;
while(y){
if(y&1)res=(res+x)%MOD;
x=(x+x)%MOD;
y/=2;
}
return res;
}
struct nn{
LL a[5][5];
void INIT(){
a[1][1]=a[1][2]=a[2][1]=a[2][2]=0;
}
};
nn MUL(nn A,nn B){
nn X;
rep(i,1,2)rep(j,1,2){
X.a[i][j]=0;
rep(k,1,2)X.a[i][j]+=MSC(A.a[i][k],B.a[k][j]),X.a[i][j]%=MOD;
}
return X;
}
nn KSM(nn X,LL y){
nn res;
res.INIT();
res.a[1][1]=res.a[2][2]=1;
while(y){
if(y&1)res=MUL(res,X);
X=MUL(X,X);
y/=2;
}
return res;
}
void READ(){
scanf("%lld%lld%lld%lld%lld%lld",&MOD,&ra,&c,&Xl,&n,&G);
}
void SOLVE(){
nn A;
A.INIT();
A.a[1][1]=ra;A.a[2][1]=c;A.a[2][2]=1;A.a[1][2]=0;
A=KSM(A,n);
printf("%lld\n",(MSC(Xl,A.a[1][1])+A.a[2][1])%MOD%G);
}
int main(){
READ();
SOLVE();
return 0;
}