[题解]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;
}
posted @ 2019-10-29 17:27  硫氯  阅读(110)  评论(0编辑  收藏  举报