[NOI2012] 随机数生成器

题目链接

这道题看上去是一个递推题,但是 n < 1 0 18 n<10^{18}
递推是要T的节奏啊
所以怎么办呢?
我们看到这个递推的方程非常的短
X n + 1 = ( a X n + c ) m o d ( m ) X_{n+1}=(aX_n+c)mod(m)
并且要在 l o g n logn 的时间内做出来,我们想到了矩阵乘法!
我们构造一下
[ X i 1 ] [ a 0 c 1 ] = [ X i + 1 1 ] \left[ \begin{matrix} X_i & 1 \\ \end{matrix} \right] \cdot \left[ \begin{matrix} a & 0 \\ c & 1 \end{matrix} \right]= \left[ \begin{matrix} X_{i+1} &1 \\ \end{matrix} \right]

就很简单了,答案就是前面那个矩阵乘上后面那个矩阵的 n n 次方

有几点需要注意的

  1. 在前面矩阵乘法的时候要 m o d mod m m ,而不是 m o d mod g g ,我开始在这里看错了结果本来写的矩阵乘法什么的都对了还是调了一个小时(大雾
  2. 快速幂的时候需要把初始矩阵设成单位矩阵
    [ 1 0 0 1 ] \left[ \begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right]
  3. 需要龟速乘,因为可能会炸 l o n g long l o n g long
  4. 不要把龟速乘写成快速幂(比如说我…)
  5. 建议把矩阵结构体封装一下,这样可以不用写 m u l s e l f mulself
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

# define int long long

int m,A,c,x0,n,g;

int mul(int a,int b){
	int res=0;
	while(b){
		if(b&1)res=(res+a)%m;
		a=(a+a)%m;
		b>>=1;
	}
	return res;
}

struct matrix{
	int a[3][3];
	int x,y;
	matrix(){
		memset(a,0,sizeof(a));
		x=0,y=0;	
	}
	matrix operator * (const matrix &mm)const{
		matrix res;
		res.x=x,res.y=mm.y;
		Rep(i,1,res.x)
			Rep(j,1,res.y)
				Rep(k,1,mm.x)
					res.a[i][j]=(res.a[i][j]+(mul(a[i][k],mm.a[k][j]))%m)%m;
		return res;
	}
}ans,a,b;	

matrix Qpow(matrix base,int ind){
	matrix res;
	res.x=2,res.y=2;
	res.a[1][1]=1,res.a[2][2]=1;
	while(ind){
		if(ind&1)res=res*base;
		base=base*base;
		ind>>=1;
	}
	return res;
}

signed main()
{
	read(m),read(A),read(c),read(x0),read(n),read(g);
	a.x=1,a.y=2;
	a.a[1][1]=x0,a.a[1][2]=1;
	b.x=2,b.y=2;
	b.a[1][1]=A,b.a[1][2]=0;
	b.a[2][1]=c,b.a[2][2]=1;
	b=Qpow(b,n);
	ans=a*b;
	printf("%lld\n",ans.a[1][1]%g);
	return 0; 
}
发布了45 篇原创文章 · 获赞 52 · 访问量 9649

猜你喜欢

转载自blog.csdn.net/devout_/article/details/104146962
今日推荐