【题目大意】
f(i)=((Af(i-1)+B)/(Cf(i-1)+D)) mod P。
给出f(0), A, B, C, D, P, n,求f(n)。
多组数据T<=1e4
n<=1e18, P <= 1e9, |f(0)|,|A|,|B|,|C|,|D| <= 1e9
保证任何时候存在逆元。
【题解】
首先我们有一种O(TP)的做法:找循环节。
考场上因为数据原因是可以AC的。。
# include <map> # include <stdio.h> # include <assert.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; # define RG register # define ST static int A, B, C, D, mod, lm, rm; ll f[2000010], n; map<int, int> mp; inline ll exgcd(ll a, ll b, ll &x, ll &y) { if(b == 0) { x = 1; y = 0; return a; } exgcd(b, a%b, x, y); ll t = x; x = y; y = t - (a/b)*y; } inline ll getinv(ll n) { ll x, y; exgcd(n, (ll)mod, x, y); x = (x%mod + mod) % mod; return x; } inline void sol() { scanf("%lld%d%d%d%d%lld%d", &f[0], &A, &B, &C, &D, &n, &mod); A = (A+mod)%mod; B = (B+mod)%mod; C = (C+mod)%mod; D = (D+mod)%mod; mp.clear(); lm = rm = -1; mp[f[0]] = 0; for (int i=1; i<=mod; ++i) { f[i] = (A*f[i-1] + B) % mod * getinv(C*f[i-1] + D) % mod; if(mp.find(f[i]) != mp.end()) { lm = mp[f[i]], rm = i; break; } mp[f[i]] = i; } // printf("%d %d ", lm, rm); assert(lm != -1 && rm != -1); if(n <= lm) printf("%lld ", f[n]); else printf("%lld ", f[(n-lm)%(rm-lm)+lm]); } int main() { freopen("exercise.in", "r", stdin); freopen("exercise.out", "w", stdout); int T; cin >> T; while(T--) sol(); return 0; }
标准做法是
f(i)=((Af(i-1)+B)/(Cf(i-1)+D))
f(i-1)=((Af(i-2)+B)/(Cf(i-2)+D))
那么
f(i)=((A^2+BC)f(i-2)+(AB+BD))//((AC+CD)f(i-2)+(CD+D^2))
相当于两个2*2的矩阵乘在一起。
那么矩乘即可。
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; # define RG register # define ST static int f0, A, B, C, D, mod, ans; ll n; inline ll exgcd(ll a, ll b, ll &x, ll &y) { if(b == 0) { x = 1; y = 0; return a; } exgcd(b, a%b, x, y); ll t = x; x = y; y = t - (a/b)*y; } inline int getinv(ll n) { ll x, y; exgcd(n, (ll)mod, x, y); x = (x%mod + mod) % mod; return x; } struct matrix { int a[3][3], n; inline void set() {memset(a, 0, sizeof a);} friend matrix operator * (matrix a, matrix b) { matrix c; c.set(); for (int i=1; i<=2; ++i) for (int j=1; j<=2; ++j) for (int k=1; k<=2; ++k) (c.a[i][j] += 1ll * a.a[i][k] * b.a[k][j] % mod) %= mod; return c; } friend matrix operator ^ (matrix a, ll b) { matrix c; c.set(); c.a[1][1] = c.a[2][2] = 1; while(b) { if(b&1) c=c*a; a=a*a; b >>= 1; } return c; } }E; inline void sol() { scanf("%d%d%d%d%d%lld%d", &f0, &A, &B, &C, &D, &n, &mod); A = (A+mod) % mod; B = (B+mod) % mod; C = (C+mod) % mod; D = (D+mod) % mod; E.set(); E.a[1][1] = A, E.a[1][2] = B, E.a[2][1] = C, E.a[2][2] = D; E = E^n; A = E.a[1][1], B = E.a[1][2], C = E.a[2][1], D = E.a[2][2]; ans = getinv((ll)C * f0 + D); ans = 1ll * ans * (1ll * A * f0 % mod + B) % mod; printf("%d ", ans); } int main() { freopen("exercise.in", "r", stdin); freopen("exercise.out", "w", stdout); int T; cin >> T; while(T--) sol(); return 0; }