• 万能欧几里得知识整理


    题目

      LOJ#6440

    解析

      以坐标原点为起点,将矩阵$A$看作向右走,$B$看作向上走,平面上的点$(x, y)$有贡献$A^xB^y$,答案就是$y=left lfloor frac{Px+R}{Q} ight floor(1 leqslant x leqslant L)$每一个$x$下第一个整点的贡献和。

      来一发课件,下图中斜线段即为$y=left lfloor frac{Px+R}{Q} ight floor$

     

       操作序列满⾜信息可合并。只需要两个操作序列的信息,即可计算出将这两个操作序列拼接后的信息。

      操作可以被看成代码段:

      初始化: matrix curA =​ $I$, curB = $B$ ^ floor(R/Q), sum = $0$

      U: curB = curB * B;

      R: curA = curA * A, sum += curA * curB;

      因此一个操作序列段需要维护的信息有curA, curB, sum

      

      实现一个函数$solve(P, Q, R, L, A, B)$, $A$、$B$为操作序列段,即由$U$和$R$组合而成的段。该函数代表了一个操作序列段,生成序列有$L$个$B$,编号为$1sim L$。第$i-1$个$B$与第$i$个$B$之间有$left lfloor frac{Pi+R}{Q} ight floor-left lfloor frac{P(i-1)+R}{Q} ight floor$个$A$,也就是说这里是以原点为起点,将操作$B$看作向右走,操作$A$看作向上走,斜线为$y=left lfloor frac{Pi+R}{Q} ight floor$。

      根据这个函数的定义,有如下两个性质:

        R = R mod Q :⽆影响
        P = P mod Q :B = A ^ floor(R/Q) * B
      现在考虑$P<Q, R<Q$时的情况:
        对于第$x$个$A$,若第$y$个$B$为第$x$个$A$后的$B$,则满足:$$x leqslant left lfloor frac{Py+R}{Q} ight floor \ Qx leqslant Py+R \ left lceil frac{Qx-R}{P} ight ceil leqslant y \ left lfloor frac{Qx-R+P-1}{P} ight floor leqslant y $$
        也就是说第$x$个$A$前有$left lfloor frac{Qx-R-1}{P} ight floor$个$B$,第$x-1$个$A$与第$x$个$A$之间有$left lfloor frac{Qx-R-1}{P}  ight floor-left lfloor frac{Q(x-1)-R-1}{P}  ight floor$个$B$,似乎可以递归了。但由于当$x$等于$1$时,$left lfloor frac{Q(x-1)-R-1}{P}  ight floor < 0$,因此第一个$A$需要单独计算,假设有$m$个$A$,这样的话还需要计算的$x$的范围为$2leqslant x leqslant m$,但$solve$函数的$x$是从$1$开始枚举的,所以用$x-1$代替原来的$x$,于是就变成了,第$x-1$个$A$与第$x$个$A$之间有$left lfloor frac{Qx+Q-R-1}{P}  ight floor-left lfloor frac{Q(x-1)+Q-R-1}{P}  ight floor$个$B$,此时$x$的范围为$1leqslant x leqslant m - 1$,可以递归调用函数$solve(Q, P, Q - R - 1, m - 1, B, A)$。注意第$m$个$A$后可能还有一些$B$,需要在递归后统计贡献。
      递归次数等于$gcd(P, Q)$ 
      注意矩阵乘法的顺序。

     代码: 

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int mod = 998244353;
    
    ll add(ll x, ll y)
    {
        return x + y < mod? x + y: x + y - mod;
    }
    
    int n;
    
    ll qpow(ll x, ll y)
    {
        ll ret = 1;
        while(y)
        {
            if(y&1)
                ret = ret * x % mod;
            x = x * x % mod;
            y >>= 1;
        }
        return ret;
    }
    
    struct Matrix{
        ll a[25][25];
    }dw, dw0;
    
    Matrix operator + (Matrix x, Matrix y)
    {
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                x.a[i][j] = add(x.a[i][j], y.a[i][j]);
        return x;
    }
    
    Matrix operator * (Matrix x, Matrix y)
    {
        Matrix ret = dw0;
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                for(int k = 1; k <= n; ++k)
                    ret.a[i][j] = add(ret.a[i][j], x.a[i][k] * y.a[k][j] % mod);
        return ret;
    }
    
    Matrix mat_qpow(Matrix x, ll y)
    {
        Matrix ret = dw;
        while(y)
        {
            if(y&1)
                ret = ret * x;
            x = x * x;
            y >>= 1;
        }
        return ret;
    }
    
    struct node{
        Matrix curA, curB, sum;
        node(){}
        node(Matrix x, Matrix y, Matrix z) {
            curA = x;
            curB = y;
            sum = z;
        }
    };
    
    node operator + (node x, node y)
    {
        return node(x.curA * y.curA, x.curB * y.curB, x.sum + x.curA * y.sum * x.curB);//计算sum时注意顺序
    }
    
    node qsum(node x, ll y)
    {
        node ret = node(dw, dw, dw0);
        while(y)
        {
            if(y&1)
                ret = ret + x;
            x = x + x;
            y >>= 1;
        }
        return ret;
    }
    
    ll calc(ll P, ll Q, ll R, ll L)//计算floor((P*L+R)/Q)
    {
        return (ll)((long double)P / Q * L + (long double)R / Q) ;
    }
    
    node solve(ll P, ll Q, ll R, ll L, node A, node B)
    {
        if(L == 0)    return node(dw, dw, dw0);
        R %= Q;
        if(P >= Q)    return solve(P % Q, Q, R, L, A, qsum(A, P / Q) + B);
        ll m = calc(P, Q, R, L);
        if(m <= 0)    return qsum(B, L);
        ll cnt = L - calc(m, P, P - R - 1, Q) + 1;
        return qsum(B, (Q - R - 1) / P) + A + solve(Q, P, Q - R - 1, m - 1, B, A) + qsum(B, cnt);
    }
    
    int main()
    {
        ll P, Q, R, L;
        scanf("%lld%lld%lld%lld%d", &P, &Q, &R, &L, &n);
        Matrix A, B;
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                scanf("%lld", &A.a[i][j]);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                scanf("%lld", &B.a[i][j]);
        for(int i = 1; i <= n; ++i)
            dw.a[i][i] = 1;
        node u = node(dw, B, dw0), r = node(A, dw, A);
        node ans = qsum(u, R / Q) + solve(P, Q, R, L, u, r);
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n; ++j)
                printf("%lld ", ans.sum.a[i][j]);
            printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/12418228.html
Copyright © 2020-2023  润新知