「wiki1281」Xn数列
题目描述 Description
给你6个数,m, a, c, x0, n, g
Xn+1 = ( aXn + c ) mod m,求Xn
m, a, c, x0, n, g<=10^18
输入描述 Input Description
一行六个数 m, a, c, x0, n, g
输出描述 Output Description
输出一个数 Xn mod g
样例输入 Sample Input
11 8 7 1 5 3
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
int64按位相乘可以不要用高精度。
题解
由题目中 Xn+1 = (a * Xn + c) % m 可得以下矩阵:
┏ a, 0 ┓
[Xn, c] * ┃ ┃ = [Xn+1, c]
┗ 1, 1 ┛
于是做矩阵快速幂即可。
注意到m, a, c, x0, n, g <= 1018,其中a,c,X0 是非负整数,m,n,g 是正整数,所以我们对于取模运算进行一个修改,将乘法修改为倍增乘法(类似于快速幂):
long long Multiply (long long x, long long y)
{
long long ans = 0;
while(y)
{
if(y & 1) ans = (ans + x) % m;
x = (x << 1) % m;
y >>= 1;
}
return ans;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include<cstdio> #include<iostream> #define ll long long using namespace std; ll m,a,c,x0,n,g; ll x[2][2],b[2][2],f[1][2]; ll mul(ll a,ll b,ll t) { ll ans=0; while(b) { if(b&1)ans=(ans+a)%t; b>>=1; a=(a<<1)%t; } return ans; } void mmul(ll x[2][2],ll b[2][2],ll ans[2][2]) { ll t[2][2]; for(int i=0;i<2;i++) for(int j=0;j<2;j++) { t[i][j]=0; for(int k=0;k<2;k++) t[i][j]=(t[i][j]+mul(x[i][k],b[k][j],m))%m; } for(int i=0;i<2;i++) for(int j=0;j<2;j++) ans[i][j]=t[i][j]; } void mmul2(ll x[1][2],ll b[2][2],ll ans[1][2]) { ll t[1][2]; for(int j=0;j<2;j++) { t[0][j]=0; for(int k=0;k<2;k++) t[0][j]=(t[0][j]+mul(x[0][k],b[k][j],m))%m; } for(int j=0;j<2;j++) ans[0][j]=t[0][j]; } int main() { scanf("%lld%lld%lld%lld%lld%lld",&m,&a,&c,&x0,&n,&g); x[0][0]=a; x[1][0]=x[1][1]=1; b[0][0]=b[1][1]=1; f[0][0]=x0;f[0][1]=c; while(n) { if(n&1)mmul(x,b,b); n>>=1; mmul(x,x,x); } mmul2(f,b,f); printf("%lld\n",f[0][0]%g); return 0; } |
Subscribe