BZOJ5418 NOI2018屠龙勇士EXCRT
https://www.lydsy.com/JudgeOnline/problem.php?id=5418
题目描述
小D 最近在网上发现了一款小游戏。游戏的规则如下:
-
游戏的目标是按照编号1→n1 \rightarrow n1→n 顺序杀掉n条巨龙,每条巨龙拥有一个初始的生命值ai。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 pi ,直至生命值非负。只有在攻击结束后且当生命值恰好为 0 时它才会死去。
-
游戏开始时玩家拥有m 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一 把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。 小D 觉得这款游戏十分无聊,但最快通关的玩家可以获得ION2018 的参赛资格, 于是小D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:
-
每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作为武器。
-
机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的x 次,使巨龙的生命值减少x×ATK。
-
之后,巨龙会不断使用恢复能力,每次恢复pi 生命值。若在使用恢复能力前或某一次恢复后其生命值为0,则巨龙死亡,玩家通过本关。
那么显然机器人的攻击次数是决定能否最快通关这款游戏的关键。小 D 现在得知了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数x设置为多少,才能用最少的攻击次数通关游戏吗?
当然如果无论设置成多少都无法通关游戏,输出−1 即可。
输入输出格式
输入格式:
从文件dragon.in 中读入数据。
第一行一个整数T ,代表数据组数。
接下来T 组数据,每组数据包含5行。
-
每组数据的第一行包含两个整数,n和m,代表巨龙的数量和初始剑的数量;
-
接下来一行包含n个正整数,第i个数表示第i条巨龙的初始生命值ai;
-
接下来一行包含n个正整数,第i个数表示第i条巨龙的恢复能力pi ;
-
接下来一行包含n个正整数,第i个数表示杀死第i 条巨龙后奖励的剑的攻击力;
-
接下来一行包含m个正整数,表示初始拥有的m把剑的攻击力。
输出格式:
输出到文件dragon.out 中。 一共T行。
第i 行一个整数,表示对于第i 组数据,能够使得机器人通关游戏的最小攻击次数x ,如果答案不存在,输出−1。
首先鸣谢ysy20021208帮助我踩坑,我才AC此题。
一眼扩展中国剩余定理
Pi × y+life=X×ATK
ATK×X ≡life(mod Pi)
板子题,解决!
纯属瞎扯!
国赛怎么可能这么水,即使是T1
EXCRT使用是有限制的,那就是X的系数必须为1,而现在的X系数为ATK。
这个ATK有可能在mod Pi的情况下有可能根本没有逆元,直接除更是不可以。
我们求解如何消去ATK?
使用exgcd算法求解一般的不定方程,解出特解,从而算出通解。
X×ATK+Piy=life
用exgcd求出两个特解Sx和Sy
x=Sx+k× (Pi/gcd(ATK,Pi))
两边同时取模
x≡Sx(mod Pi /gcd(ATK,Pi) )
之后EX中国剩余定理出场与前面的合并解决。
解决了吗?
没有。
如果所有的Pi=Ai的话我们解同余方程的结果将会是0.但显然不对,应该直接求出杀死每条龙所需的刀数然后所有刀数求一个lcm即可。解方程的时候要扔掉。还有就是ATK是Pi的倍数是永远杀不掉龙的。
我们在确定是哪把刀时,要开一个multiset和一个桶,这是最关键的。
最后放代码
#include<cstdio> #include<set> #include<algorithm> #include<cstring> using namespace std; #define N 1000001 typedef long long ll; multiset <ll> s; ll m[N]; ll a[N]; ll life[N]; ll p[N]; ll gg[N]; bool flag; ll t[N]; ll boom[N]; ll T,n,K; ll maxn; ll pow(ll x,ll y,ll mod) { ll ans=0; while(y) { if(y&1) ans=(ans+x)%mod; x=(x+x)%mod; y/=2; } return ans; } ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x=1; y=0; return a; } ll gcd=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return gcd; } ll find(ll num) { multiset <ll> ::iterator here=s.lower_bound(num); if(here==s.end()) { here--; return -*here; } else return -*here; } void in() { for(int i=1;i<=n;i++) { t[i]=find(-life[i]); s.insert(-gg[i]); boom[gg[i]]++; if((--boom[t[i]])==0) s.erase(-t[i]); } for(int i=1;i<=n;i++) maxn=max(maxn,(life[i]%t[i])?(life[i]/t[i]+1):(life[i]/t[i])); } void is() { for(int i=1;i<=n;i++) { ll x,y; ll gcd=exgcd(t[i],p[i],x,y); if(life[i]%gcd) { flag=1; return ; } x=pow(x,(life[i]/gcd),(p[i]/gcd)); a[i]=x; m[i]=p[i]/gcd; } } void init() { s.clear(); flag=0; ll x; maxn=0; memset(boom,0,sizeof(boom)); memset(m,0,sizeof(m)); memset(a,0,sizeof(a)); scanf("%lld%lld",&n,&K); for(int i=1;i<=n;i++) scanf("%lld",&life[i]); for(int i=1;i<=n;i++) scanf("%lld",&p[i]); for(int i=1;i<=n;i++) scanf("%lld",&gg[i]); for(int i=1;i<=K;i++) { scanf("%lld",&x); boom[x]++; s.insert(-x); } in(); is(); } ll China() { if(flag) return -1; ll M=m[1],olda=a[1]; for(int i=2;i<=n;i++) { ll A=M,B=m[i],d=((a[i]-olda)%B+B)%B,x,y; ll gcd=exgcd(A,B,x,y); if(d%gcd) return -1; x=pow(x,d/gcd,B/gcd); M*=B/gcd; olda=(olda+x*A)%M; } if(olda<maxn) olda=olda+M*(((maxn-olda)%M)?((maxn-olda)/M+1):((maxn-olda)/M)); else if(olda>maxn) olda=olda-M*((-maxn+olda)/M); return olda; } int main() { scanf("%lld",&T); while(T--) { init(); printf("%lld\n",China()); } return 0; }
原网站地址