2019年牛客多校第五場(BC)

B:generator 1

題意

給你x0,x1,a,b,xi=axi1+bxi2x_0,x_1,a,b, x_i=ax_{i-1}+bx_{i-2}讓你求出xnx_n

思路

典型的矩陣快速冪,但是n的範圍太大,所以得快速冪得用十進制快速冪

#include<bits/stdc++.h>
using namespace std;
  
#define ll long long
const int maxn = 1e6 + 5;
ll mod;
  
struct Matrix{
    ll mat[2][2];
  
    Matrix() {memset(mat, 0, sizeof(mat));};
  
    void init() {
        mat[0][0] = mat[1][1] = 1;
    }
  
    void init(ll a, ll b) {
        mat[0][0] = 0; mat[0][1] = b;
        mat[1][0] = 1; mat[1][1] = a;
    }
  
    void operator = (Matrix x) {
        for (int i = 0; i <= 1; i ++)
            for (int j = 0; j <= 1; j ++)
                mat[i][j] = x.mat[i][j];
    }
  
};
  
void Print(Matrix x) {
    for (int i = 0; i <= 1; i ++) {
        for (int j = 0; j <= 1; j ++)
            cout << x.mat[i][j] << " ";
        cout << endl;
    }
}
  
Matrix operator * (Matrix x, Matrix y) {
    Matrix t;
    for (int i = 0; i <= 1; i ++)
        for (int j = 0; j <= 1; j ++)
            for (int k = 0; k <= 1; k ++)
                t.mat[i][j] = (t.mat[i][j] + x.mat[i][k] * y.mat[k][j]) % mod;
    return t;
}
  
Matrix Ksm(Matrix x, ll b) {
    //cout << b << endl;
    Matrix t; t.init();
    while(b) {
        if(b & 1) t = t * x;
        x = x * x;
        b >>= 1;
    }
    //Print(t);
    return t;
}
  
  
int main() {
    ll x0, x1, a, b;
    scanf("%lld %lld %lld %lld", &x0, &x1, &a, &b);
    char s[maxn];
    scanf("%s%lld", s, &mod);
    int len = strlen(s);
    reverse(s, s+len);
    Matrix t, ans; t.init(a, b);
    ans.mat[0][0] = x0; ans.mat[0][1] = x1;
    Matrix res;
    res.init();
    for (int i = 0; i < len; i ++) {
        res = res * Ksm(t, s[i]-'0');
        t = Ksm(t, 10);
       // Print(res);
       // Print(t);
    }
    ans = ans * res;
    printf("%lld\n", ans.mat[0][0]);
    return 0;
}

C:generator 2

題意

有這麼一個遞推式xi=(axi1+b)mod&ThinSpace;&ThinSpace;px_i=(a\cdot x_{i-1}+b)\mod p,讓你求vv[1,n1][1,n-1]中第一次出現的位置

思路

因爲遞推式模pp,所以xx的循環節一定小於pp

xx又是這種形式xn=a(a(a(ax+b)+b)+b)+bx_n=a(a(a(ax+b)+b)+b)+b

所以我們的任務就變成Amvmod&ThinSpace;&ThinSpace;pA^{m} \equiv v\mod p求最小的mm

A1=x,A2=(ax+b),A3=a(ax+b)+b,A4=a(a(ax+b)+b)+b)+b{A^1=x,A^2=(ax+b),A^3=a(ax+b)+b,A^4=a(a(ax+b)+b)+b)+b}

Amvmod&ThinSpace;&ThinSpace;pA^m\equiv v\mod p明顯可以用BSGS

但是BSGS的一個使用條件能不能求出AiSA^{-i*S}

但是我們怎麼求出AiSA^{-i*S}

正常的加是乘a加b,那麼除就是除a減ba\frac{b}{a}

舉個例子:

x0=x,x1=ax+b,x2=a(ax+b)+b,x3=a(a(ax+b)+b)+bx_0=x,x_1=ax+b,x_2=a(ax+b)+b,x_3=a(a(ax+b)+b)+b

我們從x3x_3降到x1x_1,x3x_3先除aa再減去ba\frac{b}{a}變成x2x_2,然後再除aa減去ba\frac{b}{a}變成x1x_1

那我們從A2S+jA^{2S+j}降到AS+jA^{S+j}只需要進行SS次操作即可

這樣我們就可以用BSGS了

跟BSGS的步驟差不多,我們可以把式子化成 AiS+jvmod&ThinSpace;&ThinSpace;pA^{i*S+j}\equiv v\mod p

我們可以預處理出來ASA^S ,然後遍歷找到一個AjvAiSmod&ThinSpace;&ThinSpace;pA^j\equiv v*A^{-i*S}\mod p

也就是說在這個式子中AiSA^{-i*S}不是一個值,而是一種操作,把vv所代表的次數降下SS

x0=1,x1=21+1,x2=,x4=15,x5=31x_0=1,x_1=2*1+1,x_2=,x_4=15,x_5=31

因爲我們已經預處理了一個ASA^S,那麼在我們遍歷ii的過程中每次降下一個SS,知道找到或者找不到

用Hash存一下AjA^j

AC代碼

#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int>pis;
const int limit = 1e6;
pis d[limit+6];
int vals[limit+6], pos[limit+6];

int Ksm(ll a, int b, int p) {
    ll res = 1;
    while(b) {
        if(b & 1) res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}

int inv(int a, int p) { return Ksm(a, p-2, p); }

void solve() {
    ll n, x0, a, b, p; int Q;
    scanf("%lld %lld %lld %lld %lld %d", &n, &x0, &a, &b, &p, &Q);
    if(!a) {
        while(Q --) {
            int v; scanf("%d", &v);
            if(v == x0) printf("0\n");
            else if(v == b) printf("1\n");
            else printf("-1\n");
        }
        return ;
    }
    d[0] = {x0, 0};
    for (int i = 1; i <= limit; i ++) {
        int val = (a*d[i-1].first+b) % p;
        d[i] = {val, i};
    }
    sort(d, d+limit+1);
    int cnt = 0;
    for (int i = 0; i <= limit; i ++) {
        vals[cnt] = d[i].first; pos[cnt++] = d[i].second;
        while(d[i].first == d[i+1].first && i+1 <= limit) i++;
    }
    int inv_a = inv(a, p);
    int inv_b = (p-b) % p * inv_a % p; 
    ll aa = 1, bb = 0;
    for (int i = 0; i <= limit; i ++) {
        aa = aa * inv_a % p;
        bb = (bb * inv_a + inv_b) % p;
    }
    while(Q --) {
        int v; scanf("%d", &v);
        int it = lower_bound(vals, vals+cnt, v) - vals;
        if(it < cnt && vals[it] == v) {
            if(pos[it] < n) printf("%d\n", pos[it]);
            else printf("-1\n");
            continue;
        }
        int m = p/(limit+1) + 3, flag = 0;
        for (int i = 1; i <= m; i ++) {
            v = (aa * v + bb) % p;
            it = lower_bound(vals, vals+cnt, v) - vals;
            if(it<cnt && vals[it] == v) {
                flag = 1;
                int res = i*(limit+1)+pos[it];
                if(res>=n) res = -1;
                printf("%d\n", res);
                break;
            }
        }
        if(!flag) printf("-1\n");
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while(T --) solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章