• bzoj 5418


    这是拓展crt的典型应用

    在你开始做之前,我一定要告诉你一件事情:虽然这道题看着和拓展crt模板很像,但他俩是有巨大的区别的!不要直接把板子改吧改吧扔上去!

    题目模型:求解模线性方程组

    left{egin{matrix} m1*x & equiv & a1 & mod &p1 \ m2*x & equiv & a2 & mod &p2 \ ......\ mn*xn &equiv &an &mod &pn end{matrix}
ight.

    其中p1,p2...pn不一定互质

    第一眼:拓展crt板子题!

    第二眼:等等...好像不太对

    第三眼:WTF!系数哪来的!

    我们知道,拓展crt的模板只能解决x系数为1的情况,而系数不为1的是很难做的!

    什么?直接乘逆元变成1?

    逆元不存在呢?

    我们稍微做一点推导:

    首先,我们解一下方程egin{matrix} m1*x & equiv & a1 & mod & p1 & & end{matrix}

    设这个方程的一个解是x0(这是可以使用拓展gcd求解的)

    那么这个方程的通解应该是x=x0+k*(p/gcd(p,m)),k∈Z

    那么这个通解等价于方程egin{matrix} x & equiv & x0 & mod & p/gcd(p,m) end{matrix}的解

    发现什么了吗?

    是的!我们证明了方程egin{matrix} m1*x & equiv & a1 & mod & p1 & & end{matrix}与方程egin{matrix} x & equiv & x0 & mod & p/gcd(p,m) end{matrix}等价,这样就消掉了前面那个方程的系数!

    所以,原方程组等价于这样:

    left{egin{matrix} x1 & equiv & x0 & mod & p1/gcd(p1,m1)\ x2 & equiv & x0{}' & mod &p2/gcd(p2,m2) \ ..... & & & & \ xn & equiv & x0{}'' &mod &pn/gcd(pn,mn) end{matrix}
ight.

    这就很好了,我们使用正常的拓展crt解之即可

    最后有几个细节问题:

    ①:对于ai>pi的情况,题目中给出的约束条件是pi=1,这样虽然拓展crt处理不了,但是我们可以应用特判过掉(p=1啊,多显然)

    ②:对于所有ai=pi的情况(即任一ai都=pi),只有当对应的攻击力是pi的倍数的时候才有解,否则无解,这个也要特判(有解也要特判,否则拓展crt解的结果会是0)

    ③:对于部分ai=pi的情况,如果对应攻击力不是pi的倍数则无解,但如果是pi的倍数,那么这个方程基本没用,可以替换成xequiv 0 mod 1之类的形式

    ④:题目中运算很大,对于带取模的乘法需要快速加优化!同时所有数据类型建议使用long long以免挂掉

    (求前驱那里本人使用的是treap,表示很好用)

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    #define INF 0x3f3f3f3f
    using namespace std;
    ll n,m;
    ll a[100005];
    ll b[100005];
    ll life[100005];
    ll acc[100005];
    ll p[100005];
    ll s[100005];
    int cyt=0;
    int rot=0;
    struct Treap
    {
        int lson;
        int rson;
        int huge;
        int same;
        ll val;
        int rank;
    }tree[200050];
    void update(int rt)
    {
        tree[rt].huge=tree[ls].huge+tree[rs].huge+tree[rt].same;
    }
    void lturn(int &rt)
    {
        int temp=rs;
        rs=tree[rs].lson;
        tree[temp].lson=rt;
        tree[rt].huge=tree[temp].huge;
        update(temp);
        rt=temp;    
    }
    void rturn(int &rt)
    {
        int temp=ls;
        ls=tree[ls].rson;
        tree[temp].rson=rt;
        tree[rt].huge=tree[temp].huge;
        update(temp);
        rt=temp;
    }
    void ins(int &rt,ll v)
    {
        if(!rt)
        {
            rt=++cyt;
            tree[rt].huge=1;
            tree[rt].same=1;
            tree[rt].val=v;
            tree[rt].rank=rand();
            return;
        }
        if(v==tree[rt].val)
        {
            tree[rt].huge++;
            tree[rt].same++;
            return;
        }else if(tree[rt].val>v)
        {
            ins(ls,v);
            if(tree[ls].rank<tree[rt].rank)
            {
                rturn(rt);
            }
        }else
        {
            ins(rs,v);
            if(tree[rs].rank<tree[rt].rank)
            {
                lturn(rt);
            }
        }
    }
    void del(int &rt,ll v)
    {
        if(!rt)
        {
            return;
        }
        if(tree[rt].val==v)
        {
            if(tree[rt].same>1)
            {
                tree[rt].huge--;
                tree[rt].same--;
                return;
            }else if(ls*rs==0)
            {
                rt=ls+rs;
                return;
            }else
            {
                if(tree[ls].rank<tree[rs].rank)
                {
                    rturn(rt);
                    del(rt,v);
                }else
                {
                    lturn(rt);
                    del(rt,v);
                }
            }
        }
        tree[rt].huge--;
        if(tree[rt].val>v)
        {
            del(ls,v);
        }else
        {
            del(rs,v);
        }
        update(rt);
    }
    void query_pro(int rt,ll v,int typ)
    {
        if(!rt)
        {
            return;
        }
        if(tree[rt].val==v)
        {
            acc[typ]=v;
            return;
        }else if(tree[rt].val<v)
        {
            acc[typ]=tree[rt].val;
            query_pro(rs,v,typ);
        }else
        {
            query_pro(ls,v,typ);
        }
    }
    int query_min(int rt)
    {
        if(ls&&tree[ls].val!=-INF)
        {
            return query_min(ls);
        }else if(tree[rt].val!=-INF)
        {
            return tree[rt].val;
        }else
        {
            return query_min(rs);
        }
    }
    ll pow_add(ll x,ll y,ll mod)
    {
        ll ans=0;
        while(y)
        {
            if(y%2)
            {
                ans+=x;
                ans%=mod;
            }
            y/=2;
            x+=x;
            x%=mod;
        }
        return ans;
    }
    ll gcd(ll x,ll y)
    {
        if(y==0)
        {
            return x;
        }
        return gcd(y,x%y);
    }
    void ex_gcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return;
        }
        ex_gcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-(a/b)*x;
    }
    bool makeit()
    {
        for(int i=1;i<=n;i++)
        {
            if(acc[i]%p[i]==0)
            {
                if(p[i]==life[i])
                {
                    a[i]=1;
                    b[i]=0;
                    continue;
                }else
                {
                    printf("-1
    ");
                    return 1;
                }
            }
            ll x,y;
            ll r=gcd(acc[i],p[i]);
            if(life[i]%r)
            {
                printf("-1
    ");
                exit(0);
            }
            acc[i]/=r;
            ll temp=life[i]/r;
            ll tt=p[i]/r;
            ex_gcd(acc[i],tt,x,y);
            x=(pow_add(x,temp,tt)+tt)%tt;
            b[i]=x;
            a[i]=tt;
        }
        return 0;
    }
    ll ex_crt()
    {
        ll M0=a[1];
        ll ans=b[1];
        for(int i=2;i<=n;i++)
        {
            ll r=gcd(M0,a[i]);
            ll bb=((b[i]-ans)%a[i]+a[i])%a[i];
            if(bb%r)
            {
                return -1;
            }
            bb/=r;
            ll M=M0/r;
            ll aa=a[i]/r;
            ll x,y;
            ex_gcd(M,aa,x,y);
            x=pow_add(x,bb,aa);
            ans+=x*M0;
            M0*=aa;
            ans=(ans%M0+M0)%M0;
        }
        return (ans%M0+M0)%M0;
    }
    ll T;
    int main()
    {
        scanf("%lld",&T);
        while(T--)
        {
            memset(tree,0,sizeof(tree));
            rot=0;
            cyt=0;
            ins(rot,-INF);
            scanf("%lld%lld",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&life[i]);//龙的生命力 
            }
            bool flag=0,flag1=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&p[i]);//龙的恢复力
                if(life[i]>p[i])
                {
                    flag=1;
                }
                if(life[i]!=p[i])
                {
                    flag1=1;
                }
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&s[i]);
            }
            for(int i=1;i<=m;i++)
            {
                ll x;
                scanf("%lld",&x);
                ins(rot,x);
            }
            for(int i=1;i<=n;i++)
            {
                acc[i]=0;
                query_pro(rot,life[i],i);
                if(acc[i]==-INF)
                {
                    acc[i]=query_min(rot);        
                }
                del(rot,acc[i]);
                ins(rot,s[i]);
            }
            if(!flag1)
            {
                bool flag2=0;
                ll ans=1;
                for(int i=1;i<=n;i++)
                {
                    if(life[i]%acc[i]!=0)
                    {
                        printf("-1
    ");
                        flag2=1;
                    }else
                    {
                        ll cd=gcd(ans,life[i]/acc[i]);
                        ans*=life[i]/acc[i]/cd;
                    }
                }
                if(!flag2)
                {
                    printf("%lld
    ",ans);
                }
                continue;
            }
            if(flag)
            {
                ll temp=0;
                for(int i=1;i<=n;i++)
                {
                    if(life[i]%acc[i]!=0)
                    {
                        temp=max(temp,life[i]/acc[i]+1);
                    }else
                    {
                        temp=max(temp,life[i]/acc[i]);
                    }
                }
                printf("%lld
    ",temp);
                continue;
            }
            if(makeit())
            {
                continue;
            }
            printf("%lld
    ",ex_crt());
        }
        return 0;
    }
  • 相关阅读:
    【BZOJ4915】简单的数字题(数学)
    【BZOJ2140】稳定婚姻(匈牙利算法板子题)
    【BZOJ2739】最远点(决策单调性)
    【AT3526】[ARC082C] ConvexScore(贡献转化+容斥)
    【CF1264D2】Beautiful Bracket Sequence(组合数学)
    【洛谷2561】[AHOI2002] 黑白瓷砖(Polya定理)
    【洛谷3511】[POI2010] MOS-Bridges(混合图欧拉回路)
    【洛谷4226】避难所(构造)
    【洛谷7453】[THUSCH2017] 大魔法师(线段树+矩乘)
    【洛谷3207】[HNOI2010] 物品调度(置换问题)
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9734024.html
Copyright © 2020-2023  润新知