zoukankan      html  css  js  c++  java
  • 【洛谷P4774】 [NOI2018] 屠龙勇士【exCRT】

    Description

    Solution

    首先,我们使用的武器和得到的武器是一定的,与选择的攻击次数无关,所以我们只需要一个(multiset)模拟整个过程就能预处理面对每条龙所选择的武器。

    容易发现要让巨龙在回血一定次数后死亡就类似于一个取模操作,设面对第(i)条龙是武器的攻击力为(atk_i),于是有(x imes atk_iequiv a_ipmod {p_i})

    于是原问题就等价于一个方程组。。。等价吗?

    (a_i> p_i)的时候,攻击(k)次有可能虽然满足上面这个方程,但是(x imes atk_i<a_i)!,这并不会让巨龙死亡。

    怎么办呢?增加一个限制条件?仔细分析数据范围,你会发现:所有没有保证(a_ile p_i)的数据都保证(p_i=1),这种情况下答案显然是(Max_{i=1}^{n}lceil frac{a_i}{atk_i} ceil),直接特判即可。

    回到上面的方程,(x imes atk_iequiv a_ipmod {p_i}),我们很想将它化成一个(exCRT)能求解的形式,即(xequiv ypmod{p_i}),于是将原方程化为(x imes atk_i+b imes p_i=a_i)(exgcd)求出它的解即可改写成一次项系数为(0)的方程,注意这个方程可能无解,需要特判。

    一波操作之后,我们终于化成了我们熟悉的形式,(exCRT)求解即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    int T,n,m;
    ll a[N],p[N],at[N],r[N],v[N<<1];
    inline void init(){
    	multiset<ll> s;
    	for(int i=1;i<=m;++i) s.insert(v[i]);
    	for(int i=1;i<=n;++i){
    		multiset<ll>::iterator it=s.upper_bound(a[i]);
    		if(it!=s.begin()) it--;
    		at[i]=*it;s.erase(it);
    		s.insert(v[m+i]); 
    	} 
    }
    inline void exgcd(ll a,ll b,ll &x,ll &y){
    	if(!b){x=1;y=0;return ;}
    	exgcd(b,a%b,x,y);
    	ll t=x;x=y;y=t-a/b*y;
    }
    int flag;
    inline ll add(ll x,ll y,ll mod){return (x+y)%mod;}
    inline ll dec(ll x,ll y,ll mod){return ((x-y)%mod+mod)%mod;}
    inline ll mul(ll x,ll y,ll mod){
    	ll z=(long double)x/mod*y;
    	return ((x*y-z*mod)%mod+mod)%mod;
    }
    inline void getans(int tp,ll a,ll b,ll c,ll &x,ll &y,ll &mod){
    	ll g=__gcd(a,b);
    	if(c%g){x=-1;return ;}
    	if(tp==1) mod/=g;
    	exgcd(a,b,x,y);
    	ll t=c/g;
    	x=mul(x,t,mod);y=mul(y,t,mod);
    }
    
    inline ll gcd(ll x,ll y){return (y==0)?x:gcd(y,x%y);}
    inline ll excrt(){
    	for(int i=1;i<=n;++i){
    		ll y;
    		flag=0;getans(1,at[i],p[i],a[i],r[i],y,p[i]);
    		if(r[i]==-1) return -1;
    	}
    	for(int i=2;i<=n;++i){		 
    		ll x,y;
    		ll nmod=(p[i-1]/gcd(p[i-1],p[i]))*p[i];
    		getans(2,p[i-1],p[i],dec(r[i],r[i-1],nmod),x,y,nmod);
    		p[i]=nmod;r[i]=add(mul(x,p[i-1],nmod),r[i-1],nmod);
    		if(r[i]==-1) return -1;
    	}
    	return r[n];
    }
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&m);
    		int flag=0;
    		for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
    		for(int i=1;i<=n;++i){
    			scanf("%lld",&p[i]);
    			if(p[i]!=1) flag=1;
    		}
    		for(int i=1;i<=n;++i) scanf("%lld",&v[m+i]);
    		for(int i=1;i<=m;++i) scanf("%lld",&v[i]);
    		init();
    		if(!flag){
    			ll ans=0;
    			for(int i=1;i<=n;++i){
    				ll t=a[i]/at[i];if(a[i]%at[i]) ++t;
    				ans=max(ans,t);
    			}
    			printf("%lld
    ",ans);
    			continue;
    		}
    		ll ans=excrt();
    		if(ans==-1) puts("-1");
    		else printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    无线电频谱和波段划分
    数字IC设计工程师推荐用书
    Verilog HDL 经典用书
    Interfacing Two Clock Domains
    值得借鉴的Perl学习总结
    MIMO技术原理、概念、现状简介
    cs0016:未能写入输出文件 "c:"WINDOWS"Microsoft.NET"Framework"v2.0.50727"Temporary ASP.NET Files"root"...."*.dll“拒绝访问”
    Sql Server 2005 数据库备份还原后出现“受限制用户”问题的解决
    两个路由器连接的连接方法
    2个表之间复制数据
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14359375.html
Copyright © 2011-2022 走看看