zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    布局重用 include merge ViewStub
    AS 常用插件 MD
    AS 2.0新功能 Instant Run
    AS .ignore插件 忽略文件
    AS Gradle构建工具与Android plugin插件【大全】
    如何开通www国际域名个人网站
    倒计时实现方案总结 Timer Handler
    AS 进行单元测试
    RxJava 设计理念 观察者模式 Observable lambdas MD
    retrofit okhttp RxJava bk Gson Lambda 综合示例【配置】
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14430864.html
Copyright © 2011-2022 走看看