zoukankan      html  css  js  c++  java
  • NOI2018屠龙勇士(扩展CRT + splay(multiset))

    这里写图片描述
    这里写图片描述
    这里写图片描述

    QWQ 一到假期就颓废 哎

    今年新鲜出炉的NOI题,QwQ同步赛的时候写的,后来交了一发洛谷,竟然过了

    首先 根据题目,我们很容易得到,假设对应每一条龙的剑的攻击力是(atk)的话

    [a_i-x imes atk + k *p_i = 0 ]

    [x imes atk = a_i pmod {p_i} ]

    QwQ一看到这个式子,就想到了扩展crt求解。

    不过我一开始的想法是,根据扩欧,求$a_i-x imes atk + k *p_i = 0 (中的每一个)x$的通解表达式,然后把它写成同余的形式,最后再用扩展CRT合并

    但是因为有点麻烦 所以没写

    这里提供(was_n)爷的做法

    就是通过求逆元,直接把(atk)弄到等式的右边

    只有当一个数和模数互质,他们才会有逆元

    我们知道$$a_i-x imes atk + k *p_i = 0 $$
    所以$$a_i= x imes atk + k *p_i$$
    然后这个方程有解的条件是(a_i | gcd(atk,p_i))

    那么我们先把等式两边同时除以(gcd(atk,p_i)) ,再写成同余式子的形式$$x imes frac{atk}{gcd} = frac{a_i}{gcd} pmod {frac{p_i}{gcd}}$$

    此时 $ frac{atk}{gcd}(和)frac{p_i}{gcd}$是互质的,所以一定存在逆元,然后就可以化成扩展crt的形式,之后求解就行

    至于每一次确定(atk)的过程,只需要一颗平衡树就行,不过要注意,可能会存在重复的元素,所以理论上不能用(set)

    哦对!一个重要的事情!

    在crt和一开始乘逆元的过程中,会爆long long,所以需要快速乘来进行乘法!这里一定要注意!
    以后遇到这种题,要想到快速乘!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define ll long long
     
    using namespace std;
    
    inline ll read()
    {
      ll x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 3e5+1e2;
    
    ll lif[maxn],p[maxn],a[maxn],m[maxn];
    ll atk[maxn];
    
    ll sz[maxn],ch[maxn][4],fa[maxn];
    ll cnt[maxn],size=2,n,mm,root,t;
    ll val[maxn];
    ll jiangli[maxn];
    bool flag=true;
    
    ll mul(ll i,ll j,ll p)
    {
        ll ans=0;
        while (j){
            if (j&1) ans=(ans+i)%p;
            i=(i+i)%p;
            j>>=1;
        }
        return ans;
    }
    
    ll son (ll x)
    {
        if (x==ch[fa[x]][0]) return 0;
        else return 1;
    }
    
    void update(ll x)
    {
        sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
    }
    
    void rotate(ll x)
    {
        ll y=fa[x],z=fa[y];
        ll b=son(x),c=son(y);
        ch[z][c]=x;
        fa[x]=z;
        ch[y][b]=ch[x][!b];
        fa[ch[x][!b]]=y;
        ch[x][!b]=y;
        fa[y]=x;
        update(y);
        update(x);
    }
    
    void splay(ll x,ll p)
    {
        while (fa[x]!=p)
        {
            ll y=fa[x],z=fa[y];
            if (z==p) rotate(x);
            else
            if (son(x)==son(y))
            {
                rotate(y);
                rotate(x);
            }
            else
            {
                rotate(x);
                rotate(x);
            }
        }
        if (fa[x]==0) root=x;
    }
    
    ll find_qq(ll x)
    {
        ll now = root,num=0;
        while (now)
        {
            if (val[now]<x)
            {
                num=now;
                now=ch[now][1];
            }
            else
              now=ch[now][0];
        }
        return num;
    }
    
    ll find_hj(ll x)
    {
        ll now = root,num=0;
        while (now)
        {
            if (val[now]>x)
            {
                num=now;
                now=ch[now][0];
            }
            else
              now=ch[now][1];
        }
        return num;
    }
    
    void insert(ll x)
    {
        ll qq=find_qq(x);
        ll hj=find_hj(x);
        splay(qq,0);
        splay(hj,qq);
        ll y=ch[hj][0];
        if (cnt[y])
          cnt[y]++,update(y);
        else
        {
            size++;
            fa[size]=hj;
            cnt[size]=1;
            val[size]=x;
            sz[size]=1;
            ch[hj][0]=size;
            splay(size,0);
        }
    }
    
    void delet(ll x)
    {
        ll qq=find_qq(x);
        ll hj=find_hj(x);
        splay(qq,0);
        splay(hj,qq);
        ll y=ch[hj][0];
        if (cnt[y]>1)
          cnt[y]--,update(y);
        else
        {
            fa[y]=0;
            cnt[y]=0;
            val[y]=0;
            sz[y]=0;
            ch[hj][0]=0;
        }
    }
    
    ll gcd(ll a,ll b)
    {
        if (b==0) return a;
        else return gcd(b,a%b);
    }
    
    ll exgcd(ll &x,ll &y,ll a,ll b)
    {
        if (b==0)
        {
            x=1;
            y=0;
            return a;
        }
        ll cnt = exgcd(x,y,b,a%b);
        ll tmp = x;
        x=y;
        y=tmp-a/b*y; 
        return cnt;
    }
    
    void init()
    {
        memset(ch,0,sizeof(ch));
        memset(sz,0,sizeof(sz));
        memset(fa,0,sizeof(fa));
        memset(val,0,sizeof(val));
        memset(a,0,sizeof(a));
        memset(m,0,sizeof(m));
        val[1]=1e18;
        val[2]=-1e18;
        fa[2]=1;
        ch[1][0]=2;
        root=1;
        size=2;
        flag=true;
    }
    
    ll niyuan(ll num,ll p)
    {
        ll ymh,szh;
        exgcd(ymh,szh,num,p);
        ymh=(ymh%p+p)%p;
        return ymh;
    }
    
    ll count(ll x)
    {
        ll hj=find_qq(x+1);
        if (val[hj]==-1e18){
            ll ii = val[find_hj(val[hj])];
            delet(ii);
            return ii;
        }
        else
        {
          ll ii = val[hj];
          delet(ii);
          return ii;
        }
    }
    
    void solve1()
    {
        for (int i=1;i<=n;i++)
        {
            ll tmp = count(lif[i]);
            //cout<<tmp<<endl;
            ll gcd1=gcd(tmp,p[i]);
        //	cout<<gcd1<<endl;
            m[i]=p[i]/gcd1;
            if (lif[i]%gcd1!=0) flag=false;
            if (!flag) return;
            lif[i]=lif[i]/gcd1;
            a[i]=mul(lif[i],niyuan(tmp/gcd1,m[i]),m[i]);
            insert(jiangli[i]);
        }
    }
    
    long long solve()
    {
        ll x0=0,M=0; 
        x0=a[1];
        M=m[1];
        long long x=0,y=0;
        for (int i=2;i<=n;i++)
        {
            ll gcd1=exgcd(x,y,M,m[i]);
            if ((a[i]-x0)%gcd1!=0) flag=false;
            if (!flag) return -1;
            long long tmp = m[i]/gcd1;
            ll yyy=(a[i]-x0)/gcd1;
            yyy%=tmp;
            if (yyy<=0) yyy+=tmp;
            x=(x%tmp+tmp)%tmp; 
            x=mul(x,yyy,tmp); 
            ll ppp = M; 
            M=M/gcd1*m[i];
            ppp=(ppp%M+M)%M;
            x0=(mul(x,ppp,M)+x0%M)%M;
        }
        x0=(x0+M)%M;
        if (x0==0) x0+=M;
        return x0;
    }
    
    void solve3()
    {
        //cout<<"gg"<<endl;
        ll ans=-1e9;
        for (int i=1;i<=n;i++)
        {
            ll tmp = count(lif[i]);
            ll cnt = lif[i]/tmp;
            lif[i]=lif[i]%tmp;
            if (lif[i]>0) cnt++;
            ans=max(ans,cnt);
            insert(jiangli[i]);
        }
        cout<<ans<<endl;
    }
    
    int main()
    { 
      //freopen("dragon.in","r",stdin);
      //freopen("dragon.out","w",stdout);
      cin>>t;
      while (t--)
      {
      	 init();
      	 n=read(),mm=read();
      	 int now = 0;
      	 for (int i=1;i<=n;i++) lif[i]=read();
      	 for (int i=1;i<=n;i++) 
           {
              p[i]=read();
              if (p[i]==1) now++;
           }
      	 for (int i=1;i<=n;i++) jiangli[i]=read();
         for (int i=1;i<=mm;i++) atk[i]=read(),insert(atk[i]);
         if (now==n) {
         	solve3();
         	continue;
         }
         solve1();
         if (!flag) {
         	cout<<-1<<endl;
         	continue;
         }
         //cout<<"hhh"<<endl;
         //for (int i=1;i<=n;i++) cout<<a[i]<<endl;
         ll ans=solve();
         if (!flag) {
         	cout<<-1<<endl;
         	continue;
         }
         cout<<ans<<endl;
      }
      return 0;
    }
    
    
  • 相关阅读:
    洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…(树规)
    STREAMING #5 题解 3.高位网络
    冲刺NOIP2015提高组复赛模拟试题(五) 3.破坏基地
    冲刺NOIP2015提高组复赛模拟试题(五)2.道路修建
    冲刺NOIP2015提高组复赛模拟试题(五)1.数学作业
    洛谷P1186 玛丽卡 spfa+删边
    清北学堂 day6 花
    清北学堂 day6 兔子
    C++ STL 全排列函数
    flash分区的意义
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160917.html
Copyright © 2011-2022 走看看