原来NOI也会出裸题啊……
用multiset求出对付每一个BOSS使用的武器威力$ATK_i$,可以得到$m$个式子$ATK_ix equiv a_i mod p_i$
看起来可以直接魔改式子了……
等一下!如果$a_i > p_i$,$ATK_ix<a_i$没把BOSS打死怎么办QAQ
看数据范围,没有特性1((a_i leq p_i))的点似乎$p_i=1$?那不只要保证攻击次数能够把所有BOSS血量打到$leq 0$就行了,,,于是这个顾虑就消除了(虽然要写数据分治)
考虑上面得到的式子,很像ExCRT,但ExCRT的式子都长$x equiv b_i mod p_i$,这里的式子不长这样。于是考虑改式子。
如果$gcd(ATK_i , p_i) otmid a_i$,显然原式无解。
当$gcd(ATK_i , p_i) mid a_i$时,求出$ATK_ix + p_iy = gcd(ATK_i,p_i)(的一组解)(x_1,y_1)$,那么$ATK_ix + p_iy = a_i$的一组解就是$(frac{gcd(ATK_i,p_i)} , frac{gcd(ATK_i,p_i)})$。
那么$ATK_ix equiv a_i mod p_i$的通解就是$x equiv frac{gcd(ATK_i,p_i)} mod frac{gcd(ATK_i,p_i)}$。
这个式子长得跟ExCRT的式子相同了,直接套板子即可。
值得注意的是,因为模数可能超过int,导致可能出现乘法爆long long。解决方案是log龟速乘/long double型快速乘/__int128
还有一个细节是:因为$a_i leq p_i$所以最后答案可能是$0$,此时应该输出的是最后的模数。
#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;
#define int long long
int read(){
int a = 0;
char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
const int _ = 1e5 + 7;
map < int , int > swr;
int hp[_] , p[_] , atk[_] , Atk[_] , N , M;
void exgcd(int a , int b , int &d , int &x , int &y){
b == 0 ? (d = a , x = 1 , y = 0) : (exgcd(b , a % b , d , y , x) , y -= a / b * x);
}
int mul(int x , int y , int MOD){
int sum = 0;
x %= MOD; y %= MOD;
while(y){
if(y & 1) sum = sum + x >= MOD ? sum + x - MOD : sum + x;
x = x + x >= MOD ? x + x - MOD : x + x;
y >>= 1;
}
return sum;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
for(int T = read() ; T ; --T){
swr.clear();
N = read(); M = read();
for(int i = 1 ; i <= N ; ++i)
hp[i] = read();
bool sp = 1;
for(int i = 1 ; i <= N ; ++i)
sp &= (p[i] = read()) == 1;
for(int i = 1 ; i <= N ; ++i)
atk[i] = read();
for(int i = 1 ; i <= M ; ++i)
++swr[read()];
for(int i = 1 ; i <= N ; ++i){
auto t = swr.upper_bound(hp[i]);
if(t != swr.begin()) --t;
Atk[i] = t->first;
if(!--t->second) swr.erase(t);
++swr[atk[i]];
}
int Mod = 1 , ans = 0;
if(sp)
for(int i = 1 ; i <= N ; ++i)
ans = max(ans , hp[i] / Atk[i] + (bool)(hp[i] % Atk[i]));
else
for(int i = 1 ; i <= N ; ++i){
int a , x , y;
exgcd(Atk[i] , p[i] , a , x , y);
if(hp[i] % a){
ans = -1;
break;
}
int mod = p[i] / a;
if(x < 0) x += mod;
int tp = mul(x , hp[i] / a , mod);
int xs = (mod + tp - ans % mod) % mod;
exgcd(Mod , mod , a , x , y);
if(xs % a){
ans = -1;
break;
}
int newMod = Mod / a * mod;
if(x < 0) x += mod / a;
ans = (mul(mul(x , xs / a , mod / a) , Mod , newMod) + ans) % newMod;
Mod = newMod;
}
cout << (ans ? ans : Mod) << endl;
}
return 0;
}