bzoj 5418

 

这是拓展crt的典型应用

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

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

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

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

第一眼:拓展crt板子题!

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

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

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

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

逆元不存在呢?

我们稍微做一点推导:

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

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

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

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

发现什么了吗?

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

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

\left\{\begin{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}\right.

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

最后有几个细节问题:

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

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

③:对于部分ai=pi的情况,如果对应攻击力不是pi的倍数则无解,但如果是pi的倍数,那么这个方程基本没用,可以替换成x\equiv 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\n");
                return 1;
            }
        }
        ll x,y;
        ll r=gcd(acc[i],p[i]);
        if(life[i]%r)
        {
            printf("-1\n");
            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\n");
                    flag2=1;
                }else
                {
                    ll cd=gcd(ans,life[i]/acc[i]);
                    ans*=life[i]/acc[i]/cd;
                }
            }
            if(!flag2)
            {
                printf("%lld\n",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\n",temp);
            continue;
        }
        if(makeit())
        {
            continue;
        }
        printf("%lld\n",ex_crt());
    }
    return 0;
}

 

posted @ 2018-10-01 08:32  lleozhang  Views(159)  Comments(0Edit  收藏  举报
levels of contents