NOI2018 屠龙勇士

题目链接:
https://loj.ac/problem/2721
https://www.luogu.org/problemnew/show/P4774

显然可以发现每次使用的剑是可以用平衡树来维护,假如杀第\(i\)头龙使用攻击为\(b[i]\)的剑。
龙既然要恢复到0的血量,说明:
\(b[i]*x>=a\)
\(b[i]*x \equiv a[i](mod \; p[i])\)
对于第二个条件我们解一个同余方程组,用扩展中国剩余定理合并为一个同余方程,再根据条件一找到最小的x。注意中间运算会爆\(long long\),要用快速乘。

关于解同余方程:
有解的充要条件是\(gcd(b[i],p[i]) | a[i]\)
我们可以先将\(b,a,p\)同时除以\(gcd(b,a,p)\)再判断除后的\(gcd(b,p)==1\),不满足则无解。
再通过求\(b\)在模\(p\)意义下的逆元化为\(x \equiv a( mod \; p)\)的形式再用CRT合并。
(存在逆元的充要条件是\(gcd(b,p)==1\))。

看代码请移步,蒟蒻写的太烂,以后会更新好一点QWQ。



















































#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef  long long ll;
void exgcd(ll a,ll b,ll& d,ll& x,ll& y){
    if(!b){ d=a; x=1; y=0;}
    else{ exgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
ll inverse(ll a,ll n){
    ll d,x,y;
    exgcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}
struct node{
    node*ch[2];
    int r,cnt,s;
    ll v;
    int cmp(ll x){
        if(v==x) return -1;
        else return v<x;
    }
    void maintain(){s=ch[0]->s+ch[1]->s+cnt;}
};
void rotate(node*&o,int d){
    node*k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
node*root,*null=new node();
void insert(node*&o,ll x){
    if(o==null){
        o=new node();
        o->v=x;
        o->r=rand();
        o->ch[0]=o->ch[1]=null;
        o->cnt=1;
    }
    else{
        int d=o->cmp(x);
        if(d==-1){o->cnt++,o->s++;return;}
        insert(o->ch[d],x);
        if(o->ch[d]->r>o->r) rotate(o,d^1);
    }
    o->maintain();
}
void remove(node*&o,ll x){
    int d=o->cmp(x);
    if(d==-1){
        if(o->cnt>1) {o->cnt--,o->s--;return;}
        node*u=o;
        if(o->ch[0]!=null&&o->ch[1]!=null) {
            d=o->ch[0]->r>o->ch[1]->r;
            rotate(o,d),remove(o->ch[d],x);
        }
        else{
            if(o->ch[0]!=null) o=o->ch[0];
            else o=o->ch[1];
            delete u;
        }
    }else remove(o->ch[d],x);
    if(o!=null) o->maintain();
}
ll kth(node*o,int k){
    if(o==null) return 0;
    int s=o->ch[0]->s;
    if(k>s&&k<=s+o->cnt) return o->v;
    else if(k<=s) return kth(o->ch[0],k);
    else return kth(o->ch[1],k-s-o->cnt);
}
int rank(node*o,ll x){
    ll ans=0;
    while(o->v!=x){
        if(o->v<x) ans+=o->ch[0]->s+o->cnt,o=o->ch[1];
        else o=o->ch[0];
    }
    return ans+o->ch[0]->s+1;
}
ll getpre(node*o,ll x){
    ll ans;
    bool k=1;
    while(o!=null){
        if(o->v<=x) ans=o->v,o=o->ch[1],k=0;
        else o=o->ch[0];
    }
    if(k) return 0;
    return ans;
}
ll getnxt(node*o,ll x){
    ll ans;
    while(o!=null){
        if(o->v>x) ans=o->v,o=o->ch[0];
        else o=o->ch[1];
    }
    return ans;
}
ll ksc(ll a,ll n,ll p){
    a%=p;n%=p;
    ll ans=0;
    for(;n;n>>=1,a=(a+a)%p){
        if(n&1) ans=(ans+a)%p;
    }
    return ans;
}
void clear(node* o){
    if(o!=null){
        clear(o->ch[0]);
        clear(o->ch[1]);
        delete o;
    }
}
ll get(ll a){
    int b=getpre(root,a);
    if(b==0) b=getnxt(root,a);
    return b;
}
ll gcd (ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return (a/gcd(a,b))*b;
}
ll swd[N],_swd[N],a[N],p[N],b[N];
int main(){
//  freopen("dragon3.in","r",stdin);
    null->s=0;
    null->v=0;
    root=null;
    int n,m,t=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        root=null;
        ll mx=-2333333333333;
        for(int i=1;i<=n;i++) { cin>>a[i];}
        for(int i=1;i<=n;i++) cin>>p[i];
        for(int i=1;i<=n;i++) cin>>_swd[i];
        for(int i=1;i<=m;i++){
            cin>>swd[i];
            insert(root,swd[i]);
        }
        ll nowb=get(a[1]);
        ll lastp=p[1];
        remove(root,nowb);
        ll agcd=gcd(gcd(nowb,lastp),a[1]);
        nowb/=agcd;
        a[1]/=agcd;
        lastp/=agcd;
        b[1]=nowb;
        if(gcd(nowb,lastp)>1){
            puts("-1");
            clear(root);
            continue;
        }
        nowb=inverse(nowb,lastp);
        ll nowa=ksc(a[1],nowb,lastp);
        insert(root,_swd[1]);
        bool ok=1;
        for(int i=2;i<=n;i++){
            ll now2b=get(a[i]);
            remove(root,now2b);
            ll agcd=gcd(gcd(now2b,p[i]),a[i]);
            now2b/=agcd;
            a[i]/=agcd;
            p[i]/=agcd;
            b[i]=now2b;
            if(gcd(now2b,p[i])>1){
                puts("-1");
                clear(root);
                ok=0;
                break;
            }
            now2b=inverse(now2b,p[i]);
            ll now2a=ksc(a[i],now2b,p[i]);
            ll d,y11,y22;
            exgcd(lastp,-p[i],d,y11,y22);       
            ll kk=now2a-nowa;   
            if(kk%d!=0){
                puts("-1");
                clear(root);
                ok=0;
                break;
            }
            ll k=lastp;
            lastp=lcm(lastp,p[i]);
            nowa=((ksc(ksc((kk/d),y11,lastp),k,lastp)+nowa)%lastp+lastp)%lastp;
            insert(root,_swd[i]);
        }
        if(!ok) continue;
        for(int i=1;i<=n;i++){
            ll k=a[i]-b[i]*nowa;
            if(k>0){
                ll kk=b[i]*lastp;
                if(k%kk==0) nowa+=(k/kk);
                else nowa+=k/kk+1;
            }
        }
        cout<<nowa<<endl;
    }
    return 0;
}

    

猜你喜欢

转载自www.cnblogs.com/lsq647vsejgfb/p/9348496.html
今日推荐