校内训练0602 习题exercise

Posted 逢山开路 遇水架桥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了校内训练0602 习题exercise相关的知识,希望对你有一定的参考价值。

【题目大意】

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\n", lm, rm);
    assert(lm != -1 && rm != -1);
    if(n <= lm) printf("%lld\n", f[n]);
    else printf("%lld\n", 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;
}
View Code

标准做法是

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\n", ans);
}

int main() {
    freopen("exercise.in", "r", stdin);
    freopen("exercise.out", "w", stdout);
    int T; cin >> T;
    while(T--) sol();
    return 0;
}
View Code

 

以上是关于校内训练0602 习题exercise的主要内容,如果未能解决你的问题,请参考以下文章

9.3校内训练

2017-4-7校内训练

校内训练2019-11-15跳一跳

校内训练2019-11-15逮虾户

校内训练2019-11-15表演

PRML Chapter01 练习题Exercise