[bzoj2875][Noi2012]随机数生成器

2875: [Noi2012]随机数生成器

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 1007   Solved: 577
[ Submit][ Status][ Discuss]

Description

Input

包含6个用空格分割的m,a,c,X0,n和g,其中a,c,X0是非负整数,m,n,g是正整数。

Output

输出一个数,即Xn mod g

Sample Input


11 8 7 1 5 3


Sample Output

2


一道比较水的矩阵乘法的题。很容易可以看出我们的答案是这样得出的


然后我们在用快速幂求出前面的n次方再乘上


就行了。

需要注意的是,由于可能会在乘的时候炸掉,所以我们可以写一个快速乘,这样就不用写高精度了。

#include<iostream>
#include<cstdio>
#include<cstring>
#define F(i,x,y) for(i=x;i<=y;++i)
#include<algorithm>
using namespace std;
long long M,A,C,X0,N,G,a[2][2]={0},ans[2][2],c[2][2];
bool f=true;
long long quickcheng(long long x,long long y)
{
	long long out=0;
	x=x%M;y=y%M;
	if(x>y) swap(x,y);
	while(y)
	{
		if(y&1) out=(out+x)%M;
		y>>=1;
		x=(x+x)%M;
	}
	return out;
}
int main()
{
	long long i,j,k,y,out;
	cin>>M>>A>>C>>X0>>N>>G;
	a[0][0]=A;a[0][1]=C;a[1][0]=0;a[1][1]=1;
	y=N; 
	while(y){
		if(y&1){
			if(f){
				F(i,0,1)
				  F(j,0,1)
				    ans[i][j]=a[i][j];
				f=false;
			}
			else{
				F(i,0,1)
				  F(j,0,1)
				  {
				  	c[i][j]=0;
				  	F(k,0,1)
				  	  c[i][j]=(c[i][j]+quickcheng(a[i][k],ans[k][j]))%M;
				  }
				F(i,0,1)
				  F(j,0,1)
				    ans[i][j]=c[i][j];
			}
		}
		y>>=1;
		F(i,0,1)
		  F(j,0,1)
		  {
			c[i][j]=0;
			  F(k,0,1)
			  	c[i][j]=(c[i][j]+quickcheng(a[i][k],a[k][j]))%M;
		  }
		F(i,0,1)
		  F(j,0,1)
			a[i][j]=c[i][j];
	}
	out=(quickcheng(ans[0][0],X0)+ans[0][1])%M;
	out=out%G;
	cout<<out<<endl;
}


3332 数列

题目描述 Description

a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1]  (x>3)

求a数列的第n项对1000000007(10^9+7)取余的值。

输入描述 Input Description

第一行一个整数T,表示询问个数。

以下T行,每行一个正整数n。

输出描述 Output Description

每行输出一个非负整数表示答案

样例输入 Sample Input

3

6

8

10

样例输出 Sample Output

4

9

19

数据范围及提示 Data Size & Hint

对于30%的数据 n<=100;

对于60%的数据 n<=2*10^7;

对于100%的数据 T<=100,n<=2*10^9;

这个题和上面那个题的思路差不多。我们需要这样一个式子


然后就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define F(i,x,y) for(i=x;i<=y;++i)
#define m 1000000007
using namespace std;
int t,n;
long long a[3][3]={0},ans[3][3],c[3][3];
bool f=true;
int main()
{
	scanf("%d",&t);
	while(t--){
		int i,j,y,out,k;
		scanf("%d",&n);
		memset(a,0,sizeof(a));
		a[0][0]=a[0][2]=a[1][0]=a[2][1]=1;
		f=true;y=n-3;
		if(n<=3) printf("1\n");
		else{
			while(y){
				if(y&1){
					 if(f){
						F(i,0,2)
						   F(j,0,2)
						    ans[i][j]=a[i][j];
						f=false;
					 }
					else{
						F(i,0,2)
						  F(j,0,2)
						  {
						  	c[i][j]=0;
						    F(k,0,2)
						      c[i][j]=(c[i][j]+(a[i][k]*ans[k][j])%m)%m;
						  }
						  F(i,0,2)
						    F(j,0,2)
						      ans[i][j]=c[i][j];
				    }
				}
				y>>=1;
				F(i,0,2)
				  F(j,0,2)
				  {
				    c[i][j]=0;
				    F(k,0,2)
				      c[i][j]=(c[i][j]+(a[i][k]*a[k][j])%m)%m;
				  }
				F(i,0,2)
				  F(j,0,2)
				    a[i][j]=c[i][j];
			}
			out=(ans[0][0]+ans[0][1]+ans[0][2])%m;
			printf("%d\n",out);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值