Luogu-4774 [NOI2018]屠龙勇士

这题好像只要会用set/平衡树以及裸的\(Excrt\)就能A啊...然而当时我虽然看出是\(Excrt\)却并不会...今天又学了一遍\(Excrt\),趁机把这个坑给填了吧

现预处理一下,找出每条龙用哪吧剑,把所有龙都砍\(tmp\)刀到负血。

设之后每条龙都砍了a刀,对于第\(i\)条龙,剑的攻击力为\(w_i\),恢复能力为\(c_i\),血量为\(b_i\)

则根据题意,满足
\[ b_i-aw_i+yc_i=0 \]

\[ aw_i\equiv b_i(mod\ c_i) \]

\(w_i,b_i,c_i\)同时除以\(gcd(w_i,c_i)\)然后
\[ a\equiv b_iinv(w_i)(mod\ c_i) \]
这道题就变成了同余方程组求解:
\[ \begin{cases} a\equiv b_1inv(w_1)(mod\ c_1)\\ a\equiv b_2inv(w_2)(mod\ c_2)\\ ...\\ a\equiv b_ninv(w_n)(mod\ c_n)\\ \end{cases} \]
解出\(a\),答案就是\(a+tmp\)

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef multiset<ll> MT;
const int maxn=1e5+100;
int n,m;
ll b[maxn],c[maxn],w[maxn],a,bi,ci,k[maxn],sxz[maxn];
bool err;
MT st;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void exgcd(ll a,ll b,ll &x,ll &y){b?(exgcd(b,a%b,y,x),y-=a/b*x):(x=1,y=0);}
ll inv(ll a,ll b){ll x,y; exgcd(a,b,x,y); return (x%b+b)%b;}
ll e(ll a,ll b,ll p){
    ll x=a*b-(ll)((long double)a*b/p+0.5)*p;
    return x<0?x+p:x;
}
void excrt(ll bj,ll cj){
    if(bi==0&&ci==0){
        bi=bj,ci=cj;
        return;
    }
    ll C=bj-bi,d=gcd(ci,cj),P=ci/d*cj;
    if(C%d!=0){err=1; return;}
    ll K=e(C/d%(cj/d),inv(ci/d,cj/d),(cj/d));
    bi=(e(K,ci,P)+bi)%P,ci=P;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
        for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
        for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
        for(int i=1;i<=n;i++)
        st.clear(),bi=ci=0,err=0;
        for(int i=1;i<=m;i++)
            scanf("%lld",&a),st.insert(a),sxz[i]=a;
        sort(sxz+1,sxz+m+1);
        ll tp=0;
        for(int i=1;i<=n;i++){
            MT::iterator p=st.lower_bound(b[i]);
            if(p==st.end()||(p!=st.begin()&&*p>b[i]))
                p--;
            k[i]=*p,tp=max(tp,(b[i]-1)/k[i]+1);
            st.erase(p);
            st.insert(w[i]);
        }
        for(int i=1;i<=n;i++){
            b[i]-=tp*k[i],b[i]=(b[i]%c[i]+c[i])%c[i];
            int lp=gcd(k[i],c[i]);
            if(b[i]%lp!=0){
                err=1;
                break;
            }
            c[i]/=lp,b[i]/=lp,k[i]/=lp;
            b[i]=e(b[i],inv(k[i],c[i]),c[i]);
        }
        for(int i=1;i<=n;i++){
            excrt(b[i],c[i]);
            if(err)
                break;
        }
        if(err) printf("-1\n");
        else printf("%lld\n",(bi%ci+ci)%ci+tp);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nianheng/p/10029665.html