当前位置: 首页 > news >正文

NOI2018屠龙勇士(扩展CRT + splay(multiset))

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

QWQ 一到假期就颓废 哎

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

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

\[a_i-x\times atk + k *p_i = 0 \]
\[x\times atk = a_i \pmod {p_i}\]

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

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

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

这里提供\(was_n\)爷的做法

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

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

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

那么我们先把等式两边同时除以\(gcd(atk,p_i)\) ,再写成同余式子的形式\[x\times \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;
}

转载于:https://www.cnblogs.com/yimmortal/p/10160917.html

相关文章:

  • 4 Redis 配置文件介绍
  • 定时任务Cron常用表达式与在线生成器
  • str()函数
  • Codeforces 1087C Connect Three (思维+模拟)
  • 网络图片转换到本地并转换成base64位
  • 最新最全 中文版Pycharm 2017安装教程 Python编译器安装(小白教程)
  • Spring事务管理要点总结
  • flask实现基于elasticsearch的关键词搜索建议
  • MySQL binlog group commit--commit stage
  • 返回多个值的摘要函数
  • 解决MacOS升级后出现xcrun: error: invalid active developer path, missing xcrun的问题
  • 网络流-一江春水向东流
  • lombok @Builder注解使用的例子、反编译之后的代码详解
  • cordova编译crosswalk-webview插件报错的处理办法
  • .NET MVC 验证码
  • Logstash 参考指南(目录)
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Node 版本管理
  • Otto开发初探——微服务依赖管理新利器
  • spring-boot List转Page
  • 聊聊flink的TableFactory
  • 嵌入式文件系统
  • 数据科学 第 3 章 11 字符串处理
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 智能网联汽车信息安全
  • 《天龙八部3D》Unity技术方案揭秘
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • #etcd#安装时出错
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (笔试题)分解质因式
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (二)丶RabbitMQ的六大核心
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (一)kafka实战——kafka源码编译启动
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转) ns2/nam与nam实现相关的文件
  • (转)菜鸟学数据库(三)——存储过程
  • (转载)虚函数剖析
  • .bat批处理(六):替换字符串中匹配的子串
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • @GetMapping和@RequestMapping的区别
  • [100天算法】-二叉树剪枝(day 48)
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [acm算法学习] 后缀数组SA
  • [dfs搜索寻找矩阵中最长递减序列]魔法森林的秘密路径
  • [Docker]十二.Docker consul集群搭建、微服务部署,Consul集群+Swarm集群部署微服务实战
  • [I2C]I2C通信协议详解(二) --- I2C时序及规格指引
  • [Java并发编程实战] 共享对象之可见性
  • [JMS 3] ActiveMQ实现简单的helloworld