• P4774[NOI2018]屠龙勇士【EXCRT】


    正题

    题目链接:https://www.luogu.com.cn/problem/P4774


    题目大意

    \(n\)个龙血量为\(a_i\),回复能力为\(p_i\),死亡后掉落剑的攻击力\(t_i\)\(m\)把剑,攻击力为\(b_i\)

    \(1\)开始打,每次使用不大于当前龙血量的剑中攻击力最低的一把(没有就用攻击力最低的),造成\(x\times atk\)点伤害,然后当前的剑坏掉。

    求一个最小的\(x\)使得所有龙被攻击后血量是\(p_i\)的倍数。

    \(1\leq n,m\leq 10^5\),满足\(p=1\)或者\(a_i\leq p_i\),所有\(p_i\)的公倍数不超过\(10^{12}\)


    解题思路

    额,先用\(set\)处理出每个龙用哪把剑打\(c_i\),然后就是对于每条龙的条件就是

    \[c_ix\equiv a_i(mod\ p_i),c_ix\geq a_i \]

    后面那个条件可以去掉,我们先求出满足所有\(c_ix\geq a_i\)的最小\(x\),后面再调整。

    然后前面那个东西可以用\(EXCRT\)搞了,假设我们上一次求到的答案为\(ans\),目前\(p_i\)的公倍数是\(M\),那么现在的通解就是\(ans+Mx\)。我们需要求出一个\(x\)满足

    \[c_i(ans+Mx)\equiv a_i(mod\ p_i) \]

    \[\Rightarrow Mx+p_iy=a_i-c_i\times ans \]

    然后就可以扩欧合并了。


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #include<set>
    #define ll __int128
    using namespace std;
    ll read(){
    	ll x=0,f=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    	return x*f;
    }
    void print(ll x)
    {if(x>9)print(x/10);putchar(x%10+48);return;}
    const ll N=1e5+10;
    multiset<ll> s;
    ll n,m,T,a[N],p[N],t[N],c[N];
    ll exgcd(ll a,ll b,ll &x,ll &y){
    	if(!b){x=1;y=0;return a;}
    	ll d=exgcd(b,a%b,x,y);
    	ll z=x;x=y;y=z-a/b*y;
    	return d;
    }
    void work(){
    	n=read();m=read();s.clear();
    	ll mx=0;
    	for(ll i=1;i<=n;i++)a[i]=read();
    	for(ll i=1;i<=n;i++)p[i]=read();
    	for(ll i=1;i<=n;i++)t[i]=read();
    	for(ll i=1;i<=m;i++){
    		ll x=read();
    		s.insert(x);
    	}
    	for(ll i=1;i<=n;i++){
    		multiset<ll>::iterator it;
    		if(a[i]<*s.begin())it=s.begin();
    		else it=--s.upper_bound(a[i]);
    		c[i]=*it;s.erase(it);s.insert(t[i]);
    		mx=max(mx,(a[i]-1)/c[i]+1);
    	}
    	ll M=1,x,y,ans=0;
    	for(ll i=1;i<=n;i++){
    		ll d=exgcd(M*c[i],p[i],x,y);
    		ll w=a[i]-c[i]*ans,v=p[i]/d;
    		if(w%d){puts("-1");return;}
    		x=w/d*x%v;ans=ans+x*M;
    		M=M*v;ans=(ans%M+M)%M;
    	}
    	if(ans<mx)ans+=(mx-ans+M-1)/M*M;
    	print(ans);putchar('\n');
    }
    signed main()
    {
    	scanf("%lld",&T);
    	while(T--){work();}
    	return 0;
    }
    
  • 相关阅读:
    两数之和
    IntelliJ IDEA为类和方法自动添加注释
    IDEA main 函数的快捷键
    Mac终端开启代理
    Pycharm节能模式
    使用正则表达式替换构造字典
    使用代理爬取微信文章
    利用 Scrapy 爬取知乎用户信息
    Scrapy选择器的用法
    Scrapy命令行基本用法
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14430864.html
Copyright © 2020-2023  润新知