[NOI2012] 随机数生成器

题目链接

这道题看上去是一个递推题,但是 n < 1 0 18 n<10^{18} n<1018
递推是要T的节奏啊
所以怎么办呢?
我们看到这个递推的方程非常的短
X n + 1 = ( a X n + c ) m o d ( m ) X_{n+1}=(aX_n+c)mod(m) Xn+1=(aXn+c)mod(m)
并且要在 l o g n logn 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] [Xi1][ac01]=[Xi+11]

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

有几点需要注意的

  1. 在前面矩阵乘法的时候要 m o d mod mod m m m,而不是 m o d mod mod g g g,我开始在这里看错了结果本来写的矩阵乘法什么的都对了还是调了一个小时(大雾
  2. 快速幂的时候需要把初始矩阵设成单位矩阵
    [ 1 0 0 1 ] \left[ \begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right] [1001]
  3. 需要龟速乘,因为可能会炸 l o n g long long l o n g long long
  4. 不要把龟速乘写成快速幂(比如说我…)
  5. 建议把矩阵结构体封装一下,这样可以不用写 m u l s e l f mulself 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; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值