【[NOI2018]屠龙勇士】

发现好像都是化掉系数之后套上\(ExCrt\)的板子

这好像是一个真正的扩展扩展中国剩余定理

我们要处理的方程是这样的形式

\[c_ix\equiv b_i(mod\ a_i)\]

其中\(c\)用一个\(std::multiset\)处理就好了

好像不是普通\(excrt\)可以处理的形式啊

思考一下这个方程的本质是什么,\(c_ix=k_ia_i+b_i\)

所以如果我们有两个方程

\[c_1x\equiv b_1(mod\ a_1)\]

\[c_2x\equiv b_2(mod\ a_2)\]

我们需要像\(crt\)那样合并起来

我们开始化柿子了

\[x=\frac{k_1a_1+b_1}{c_1}=\frac{k_2a_2+b_2}{c_2}\]

所以就有

\[a_2c_1k_2+b_2c_1=a_1c_2k_1+b_1c_2\]

\[a_2c_1k_2=a_1c_2k_1+b_1c_2-b_2c_1\]

根据贝祖定理,这个方程有解条件是\(gcd(a_2c_1,a_1c_2)|(b_1c_2-b_2c_1)\)

如果有解的话,我们设\(t=gcd(a_2c_1,a_1c_2)\),两边除以\(t\)

\[\frac{a_2c_1k_2}{t}=\frac{a_1c_2k_1}{t}+\frac{b_1c_2-b_2c_1}{t}\]

显然我们可以写成一个同余式

\[\frac{a_2c_1k_2}{t}\equiv \frac{b_1c_2-b_2c_1}{t}\ (mod\ \frac{a_1c_2}{t})\]

之后设\(inv=(\frac{a_2c_1}{t},\frac{a_1c_2}{t})\),即\(\frac{a_2c_1}{t}\)\(mod\) \(\frac{a_1c_2}{t}\)意义下的乘法逆元

两边乘以\(inv\)

\[k_2\equiv inv*\frac{b_1c_2-b_2c_1}{t}\ (mod\ \frac{a_1c_2}{t})\]

改写成等式

\[k_2= inv*\frac{b_1c_2-b_2c_1}{t}+y\times\frac{a_1c_2}{t}\]

我们把\(k_2\)回带到\(c_2x=k_2a_2+b_2\)

\[c_2x=inv*\frac{b_1c_2-b_2c_1}{t}*a_2+y\times\frac{a_1c_2a_2}{t}+b_2\]

再改写成同余式

\[c_2x\equiv inv*\frac{b_1c_2-b_2c_1}{t}\%(\frac{a_1c_2}{t})*a_2+b_2(mod\ \frac{a_1c_2a_2}{t})\]

我们只需要顺次合并这些方程就好了,一旦出现无解就输出\(-1\)好了

一个坑点是\(a=1\)时解出来会是\(0\),好像和实际要求不太一样,所以对于这样情况直接模拟特判就好了

之后因为非常的懒没用快速乘,用了__int128

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define re register
#define maxn 100005
#define LL __int128
#define min(a,b) ((a)<(b)?(a):(b))
#define INF 9999999999999
#define max(a,b) ((a)>(b)?(a):(b))
#define set_it std::multiset<LL>::iterator
std::multiset<LL> s;
int n,m;
LL a[maxn],b[maxn],c[maxn],res[maxn];
LL gcd(LL a,LL b){ return !b?a:gcd(b,a%b);}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) return x=1,y=0,a;
    LL r=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return r;
}
inline LL pre(LL x)
{
    s.insert(x);
    set_it i=s.find(x);
    if(i==s.begin()) return -INF;
    --i;return *i;
}
inline void del(LL x)
{
    set_it i=s.find(x);
    s.erase(i);
}
inline int check(LL x)
{
    if(s.find(x)!=s.end()) return 1;
    return 0;
}
inline LL read()
{
    char c=getchar();
    LL x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
inline LL inv(LL a,LL b)
{
    LL x,y;
    LL r=exgcd(a,b,x,y);
    return (x%b+b)%b;
}
void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+48);
}
inline LL did(LL a,LL b)
{
    if(a%b==0) return a/b;
    return a/b+1;
}
inline void tepan()
{
    LL ans=0;
    for(re int i=1;i<=n;i++)
        ans=max(ans,did(b[i],c[i]));
    write(ans),puts("");
}
inline void solve()
{
    s.clear();
    LL x;
    int flag=0;
    n=read(),m=read();
    for(re int i=1;i<=n;i++) b[i]=read();
    for(re int i=1;i<=n;i++) a[i]=read(),flag|=(a[i]!=1);
    for(re int i=1;i<=n;i++) res[i]=read();
    for(re int i=1;i<=m;i++) x=read(),s.insert(x);
    for(re int i=1;i<=n;i++)
    {
        if(check(b[i])) c[i]=b[i],del(b[i]);
        else
        {
            LL now=pre(b[i]);
            del(b[i]);
            if(now==-INF)
            {
                set_it it=s.begin();
                c[i]=*it;
                s.erase(it);
            }
            else c[i]=now,del(now);
        }
        s.insert(res[i]);
    }
    if(!flag)
    {
        tepan();
        return;
    }
    LL a1=a[1],b1=b[1],c1=c[1];
    for(re int i=2;i<=n;i++)
    {
        LL a2=a[i],b2=b[i],c2=c[i];
        LL r=gcd(c2*a1,c1*a2);
        if((b1*c2-b2*c1)%r) 
        {
            puts("-1");
            return;
        }
        if((c2*a1/r)<(c1*a2/r)) std::swap(a1,a2),std::swap(b1,b2),std::swap(c1,c2);
        LL P=a1*c2/r,Inv=inv(c1*a2/r,a1*c2/r);
        b1=((Inv*(((b1*c2-b2*c1)/r)%P+P)%P*a2))+b2;
        a1=a1*a2*c2/r;
        c1=c2;
    }
    LL y;
    if(b1%gcd(a1,c1))
    {
        puts("-1");
        return;
    }
    LL r=exgcd(c1,a1,x,y);
    LL t=a1/r;
    x=(x*(b1/r)%t+t)%t;
    write(x);
    puts("");
}
int main()
{
    int T;
    T=read();
    while(T--) solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10205688.html
今日推荐