bzoj4490 random number generator Ⅱ Enhanced Edition

Posted by Griffin on Mon, 09 Dec 2019 09:45:36 +0100

Title Link

meaning of the title

Given the parameters \ (C_1,C_2,P \), a sequence \ (x \) of length \ (n \times m \) is generated as follows:

\(x_0 = C_1,x_1=C2\)

\(x_i=(x_{i-1}+x_{i-1}) \% P \; (i > 1)\)

Then generate a sequence \ (a \) of length \ (n \times m \) as follows

\[a_i=\sum\limits_{j=0}^ix_j^2\%P\]

Now, I will perform \ (Q \) operations, and give two parameters \ (k1,k2 \) for each operation. Represents the value of exchange \ (k1,k2 \).

Then put the sequence \ (a \) into a \ (n \times m \) grid in order.

A scheme is required to make the number from \ ((1,1) \) to \ ((n,m) \) in the least lexicographic order.

thinking

It's easy to find, in fact, it's just to find out \ (a \).

Then push it.

\[x_i^2=x_{i-1}^2+2x_{i-1}x_{i-2}+x_{i-2}^2\]
\[x_{i-1}^2=x_i^2-x_{i-2}^2-2x_{i-1}x_{i-2}\]
\[x_{i-1}^2=(x_i+x_{i-2})\times(x_i-x_{i-2}) - 2x_{i-1}x_{i-2}\]
\[x_{i-1}^2=x_{i-1}(x_i+x_{i-2}) - 2x_{i-1}x_{i-2}\]
\[x_{i-1}^2=x_ix_{i-1}+x_{i-1}x_{i-2}-2x_{i-1}x_{i-2}\]
\[x_{i-1}^2=x_ix_{i-1}-x_{i-1}x_{i-2}\]

In other words

\[x_i^2=x_{i+1}x_i-x_ix_{i-1}\]

It's easy to get

\[a_i=x_{i+1}x_i-C_1(C_2-C_1)\]

So as long as we can quickly find the \ (i \) term of Fibonacci sequence.

If every matrix is directly raised to a fast power \ (TLE \)

So we preprocess the transfer matrix of \ (FBI ﹐ 1, FBI ﹐ 2, FBI ﹐ 3... FBI ﹐ m \) and \ (FBI ﹐ m, FBI {2m}, FBI {3M}... FBI {nm} \).

For the number of \ (i \) row and \ (j \) column, directly \ (O(2^3) \)

Code

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<bitset>
#include<map>
using namespace std;
typedef long long ll;
const int N = 500000 + 100,INF = 1e9 + 7;
map<ll,ll>ma;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int C1,C2,mod,n,m,Q;
namespace FBI {
    struct node {
        int a[3][3],n,m;
        node() {
            memset(a,0,sizeof(a));
        }
        node(int x) {
            n = m = x;
            memset(a,0,sizeof(a));
            for(int i = 1;i <= x;++i) a[i][i] = 1;
        }
        node(int x,int y) {
            n = x,m = y;
            memset(a,0,sizeof(a));
        }
    };
    node operator * (const node &A,const node &B) {
        int n = A.n,m = B.m,K = A.m;
        node ret(n,m);
        for(int k = 1;k <= K;++k) {
            for(int i = 1;i <= n;++i) {
                for(int j = 1;j <= m;++j) {
                    ret.a[i][j] += 1ll * A.a[i][k] * B.a[k][j] % mod;
                    ret.a[i][j] %= mod;
                }
            }
        }
        return ret;
    }
    node fbi(1,2),tmp(2,2),lin[N],row[N];
    void pre() {
        fbi.a[1][1] = C2,fbi.a[1][2] = C1;
        tmp.a[1][1] = tmp.a[1][2] = tmp.a[2][1] = 1;
        
        row[0].n = row[0].m = 2;row[0].a[1][1] = row[0].a[2][2] = 1;
        for(int i = 1;i <= m;++i) row[i] = row[i - 1] * tmp;


        lin[0].n = lin[0].m = 2;
        lin[0].a[1][1] = lin[0].a[2][2] = 1;
        for(int i = 1;i <= n;++i) lin[i] = lin[i - 1] * row[m];
    }
    int solve(ll x) {
        if(x == -1) return (C2 - C1 + mod) % mod;
        if(x == 0) return C1;
        if(x == 1) return C2;
        --x;
        int y = x % m;
        x /= m;
        return (fbi * lin[x] * row[y]).a[1][1];
    }
    int main(ll x) {
        return (1ll * solve(x + 1) * solve(x) % mod - 1ll * C1 * (C2 - C1) % mod + mod) % mod;
    }
}
ll p(ll x,ll y) {
    ll z = (x - 1) * m + y;
    if(ma[z]) return ma[z];
    return z;
}
ll cnt = 1,ans;
void solve(int x,int y) {
    ++cnt;
    if(x == n && y == m) return;
    int down = INF,right = INF;
    if(x != n) down = FBI::main(p(x + 1,y));
    if(y != m) right = FBI::main(p(x,y + 1));
    if(down <= right) {
        ans += cnt * down % mod;
        ans %= mod;
        solve(x + 1,y);
    }
    else {
        ans += cnt * right % mod;
        ans %= mod;
        solve(x,y + 1);
    }
    return;
}
int main() {
    n = read(),m = read(),Q = read(),mod = read(),C1 = read(),C2 = read();
    for(int i = 1;i <= Q;++i) {
        ll x = read(),y = read(),tx = x,ty = y;
        if(ma[x]) tx = ma[x];
        if(ma[y]) ty = ma[y];
        ma[x] = ty;ma[y] = tx;
    }
    FBI::pre();
    if(ma[1]) ans += FBI::main(ma[1]),ans %= mod;
    else ans += FBI::main(1),ans %= mod;
    solve(1,1);
    cout<<ans;
    return 0;
}

Topics: C++