Luogu4774 NOI2018 屠龙勇士 ExCRT
作者:互联网
原来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) \not\mid 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{x_1a_i}{gcd(ATK_i,p_i)} , \frac{y_1a_i}{gcd(ATK_i,p_i)})\)。
那么\(ATK_ix \equiv a_i \mod p_i\)的通解就是\(x \equiv \frac{x_1a_i}{gcd(ATK_i,p_i)} \mod \frac{p_i}{gcd(ATK_i,p_i)}\)。
这个式子长得跟ExCRT的式子相同了,直接套板子即可。
值得注意的是,因为模数可能超过int,导致可能出现乘法爆long long。解决方案是log龟速乘/long double型快速乘/__int128
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define ll long long
//This code is written by Itst
using namespace std;
inline ll read(){
ll a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return a;
}
inline void exgcd(ll a , ll b , ll &d , ll &x , ll &y){
!b ? d = a , x = 1 , y = 0 : (exgcd(b , a % b , d , y , x) , y -= a / b * x);
}
inline ll max(ll a , ll b){
return a > b ? a : b;
}
inline ll slow_times(ll a , ll b , ll MOD){
ll ans = 0;
while(b){
if(b & 1)
ans = (ans + a) % MOD;
a = (a << 1) % MOD;
b >>= 1;
}
return ans;
}
const int MAXN = 1e5 + 10;
multiset < ll > sword;
multiset < ll > :: iterator it;
int atk[MAXN] , ATK[MAXN] , N , M;
ll ans , P , gcd , x , y , a[MAXN] , m[MAXN] , hp[MAXN] , re[MAXN];
signed main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
for(int T = read() ; T ; --T){
N = read();
M = read();
bool special = 1;
for(int i = 1 ; i <= N ; ++i)
hp[i] = read();
for(int i = 1 ; i <= N ; ++i)
special &= (re[i] = read()) == 1;
for(int i = 1 ; i <= N ; ++i)
atk[i] = read();
sword.clear();
for(int i = 1 ; i <= M ; ++i)
sword.insert(read());
for(int i = 1 ; i <= N ; ++i){
it = sword.upper_bound(hp[i]);
if(it != sword.begin())
--it;
ATK[i] = *it;
sword.erase(it);
sword.insert(atk[i]);
}
ans = 0;
if(special){
for(int i = 1 ; i <= N ; ++i)
ans = max(ans , hp[i] / ATK[i] + (hp[i] % ATK[i] ? 1 : 0));
cout << ans << '\n';
continue;
}
bool f = P = 1;
for(int i = 1 ; f && i <= N ; ++i){
exgcd(ATK[i] , re[i] , gcd , x , y);
if(hp[i] % gcd)
f = 0;
x = x % re[i];
if(x < 0)
x += re[i];
m[i] = re[i] / gcd;
a[i] = slow_times(x , hp[i] / gcd , m[i]);
}
for(int i = 1 ; f && i <= N ; ++i){
ll pre = (a[i] - ans % m[i] + m[i]) % m[i];
exgcd(P , m[i] , gcd , x , y);
if(pre % gcd)
f = 0;
x = x % m[i];
if(x < 0)
x += m[i];
ans = (ans + slow_times(slow_times(x , P , P / gcd * m[i]) , pre / gcd , P / gcd * m[i])) % (P / gcd * m[i]);
P = P / gcd * m[i];
}
cout << (f ? ans : -1) << '\n';
}
return 0;
}
标签:gcd,ll,ATK,long,ExCRT,MAXN,Luogu4774,NOI2018,式子 来源: https://www.cnblogs.com/Itst/p/10350614.html