[NOI2018]屠龙勇士

题目大意:

n条龙,每条龙有血量a和回血值p,当一条龙血量< 0时,他会不断回血直至≥0。若某一刻龙的血量为0,则该龙死亡。

你有m把剑,每把剑有攻击力atk,攻击一下造成的伤害等于atk。并且你杀死一条龙后会得到一把新的剑。

你必须要按顺序杀掉龙,并且每次选择的剑都是atk小于a且最大的那把(如果都不小于a则选atk最小的那一把),杀死后剑消失。

在打每条龙时,你必须用选择的这把剑攻击K次(对于所有n条龙,K相等),且你必须刚好把它打死。

问通过的最小K。若不存在,输出-1。

解题思路:

首先对于每条龙,攻击它的剑是确定的。我们用multiset维护一下,预处理出对于每条龙要用的剑。

其次,对于每一组数据,p要么为1,要么大于等于a。

我们对于p=1的情况,直接特判即可。

对于p大于等于a的情况,我们相当于得到了n个同余方程\(atk\times x\equiv a\pmod p\)。

首先把atk除过去(atk、a、p都先约去公因数,若约去后atk无逆元,则无解),

然后得到许多形如\(x\equiv a\pmod p\)的方程,我们要求最小公共解。

用扩展中国剩余定理即可,即用exgcd每次合并两个同余方程。

时间复杂度\(O(n\log n)\)。

C++ Code:

#include<bits/stdc++.h>
#define islose(a)if(a)goto die
using LoveLive=long long;
const int N=100005;
template<typename T>
inline void read(T&d){
	int c=getchar();d=0;
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
}
template<typename T>
T max(const T a,const T b){return a<b?b:a;}
std::multiset<LoveLive>swd;
int n,m,g[N];
LoveLive a[N],p[N],atk[N];
LoveLive gcd(LoveLive a,LoveLive b){return b?gcd(b,a%b):a;}
LoveLive exgcd(LoveLive a,LoveLive b,LoveLive&x,LoveLive&y){
	if(b){
		auto G=exgcd(b,a%b,y,x);
		y-=a/b*x;
		return G;
	}
	x=1,y=0;
	return a;
}
inline LoveLive mul(LoveLive a,LoveLive b,LoveLive p){
    auto ans=a*b-(LoveLive)((long double)a/p*b+1e-9)*p;
    return(ans+p)%p;
}
LoveLive crt(){
	LoveLive A=a[1],P=p[1],x,y,d;
	for(int i=2;i<=n;++i){
		d=exgcd(P,p[i],x,y);
		if((A-a[i])%d)return -1;
        A-=P*mul((A-a[i])/d,x,(p[i]/d));
        P=P/d*p[i];
        A=(A+P)%P;
	}
	return(A+P)%P;
}
int main(){
	int T;
	for(read(T);T--;){
		swd.clear();
		read(n),read(m);
		bool p_1=true;
		for(int i=1;i<=n;++i)read(a[i]);
		for(int i=1;i<=n;++i)read(p[i]),p_1=p_1&&p[i]==1;
		for(int i=1;i<=n;++i)read(g[i]);
		while(m--){
			int p;
			read(p);
			swd.insert(p);
		}
		for(int i=1;i<=n;++i){
			auto it=swd.upper_bound(a[i]);
			if(it!=swd.begin())--it;
			atk[i]=*it;
			swd.erase(it);
			swd.insert(g[i]);
		}
		LoveLive ans=0,aans;
		for(int i=1;i<=n;++i)
		ans=max(ans,(a[i]-1)/atk[i]+1);
		if(p_1){
			printf("%lld\n",ans);
			continue;
		}
		for(int i=1;i<=n;++i){
			auto G=gcd(p[i],atk[i]);
			islose(a[i]%G);
			p[i]/=G,atk[i]/=G,a[i]/=G;
			LoveLive x,y;
			exgcd(atk[i],p[i],x,y);
			x=(x%p[i]+p[i])%p[i];
			a[i]=mul(a[i],x,p[i]);
		}
		aans=crt();
		islose(aans==-1);
		if(aans<ans){
			int lcm=1;
			for(int i=1;i<=n;++i)lcm=lcm/gcd(lcm,p[i])*p[i];
			if(!aans)aans=lcm;else
			aans+=(ans-aans+lcm-1)/lcm*lcm;
		}
		printf("%lld\n",aans);
		continue;
		die:puts("-1");
	}
	return 0;
}

 

posted @ 2018-07-22 14:22  Mrsrz  阅读(374)  评论(0编辑  收藏  举报