NOI2018D2T1 屠龙勇士

安利一下松松松的OJ: 传送门

Description:

​ 有N条巨龙, 对于每个龙含有\(a_i\)的生命, 你有N + M把砍刀, 其中M把是直接给你的, N把是杀死对应的巨龙才能获得的, 每把砍刀除攻击外没有区别,记为\(b_i\), 每个巨龙一旦血量被砍到0即为死亡, 低于零则每秒回复\(p_i\)的血量, 现在要求你攻击每个巨龙X次, 求X的最小值或判无解.对于剑的选择, 参见具体题目.

Analysis & Solution:

​ 考虑每条龙死亡的条件:
$ A_i + P_i * k = X * b_i\( \) X * b_i \equiv A_i \pmod{P_i}\( \) X \equiv A_i * b_i^{-1} \pmod{P_i}$

​ 这样就得到了关于\(X\)的一系列同余方程.

​ 可以用ExCRT求解.

ExCRT:

		> ​		关于求解多组同余组最小整数解的模数非互质情况的算法

[
​ 然后就把两个方程合并成了一个方程, 这样就可以在\(O(nlogn)\) 内求出同余方程组的最小整数解.

然后本题目就可以在\(O(nlogn)\)内求出解, 注意取模时候用快速乘或int128, 然而€€£并不能用int128.

Code:

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef long double LD;
LL read() {
    LL x = 0, flag = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') flag *= -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 3) + (x << 1) + (ch - 48);
        ch = getchar();
    }
    return x * flag;
}
void write(LL a) {
	if(a >= 10) write(a / 10);
	putchar(a % 10 + '0');
} 

#define Maxn 100009
multiset <LL> Set;
LL a[Maxn], p[Maxn], l[Maxn], z[Maxn], sword[Maxn], csf[Maxn][3];
int n, m;
void refresh_mem() {
	clar(a, 0), clar(p, 0), clar(l, 0), clar(z, 0), clar(csf, 0);
	clar(sword, 0);
}
LL qmul(LL x, LL y, LL mod) {
    LL ret = 0;
    while(y) {
        if(y & 1) ret = (ret + x) % mod;
		(x <<= 1) %= mod, y >>= 1;
    }
    return ret;
}
LL Extend_Euclid(LL a,LL b,LL &x,LL &y){
    if(!b){
        x = 1, y = 0; 
		return a;
    }
    LL d = Extend_Euclid(b, a % b, x, y), t = x;
    x = y; y = t - a / b * y;
    return d;
}
LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
LL inv(LL a, LL b){
    LL x, y; LL t = Extend_Euclid(a, b, x, y);  
    if(t != 1) return -1;
    return (x % b + b) % b;
}
int merge(LL &a1, LL &n1, LL a2, LL n2) {
	LL d = gcd(n1, n2), c = a2 - a1, tmp1, tmp2;
	if(c % d != 0) return 0;
	c = (c % n2 + n2) % n2 / d;
	n1 /= d, n2 /= d;
	c = ((__int128)c) * inv(n1, n2) % n2;
	tmp2 = n1 * n2 * d;
	c = ((((__int128)c) * n1 % tmp2 * d % tmp2) + a1) % tmp2;
	tmp1 = (c + tmp2) % tmp2;	
	a1 = tmp1, n1 = tmp2;
	return 1;
}
LL ExCRT(int cnt_equ) {
	LL a1 = csf[1][1], n1 = csf[1][2]; // remainder & mod 
	rep(i, 2, cnt_equ) if(!merge(a1, n1, csf[i][1], csf[i][2])) return -1;
	return (a1 % n1 + n1) % n1;
}
void solve() { cout << ExCRT(n) << endl; }
int main() {
	int T = read();
	while(T--) {
		refresh_mem();
		LL LM = -1;
		n = read(), m = read();
		Set.clear();
		rep(i, 1, n) a[i] = read();
		rep(i, 1, n) p[i] = read(), LM = max(LM, p[i]);
		rep(i, 1, n) z[i] = read();
		rep(i, 1, m) l[i] = read(), Set.insert(l[i]);
		Set.insert((LL)1e13);
		rep(i, 1, n) {
			set<LL> :: iterator tmp = Set.upper_bound(a[i]);
			if(tmp != Set.begin()) --tmp;
			sword[i] = *tmp; Set.erase(tmp); Set.insert(z[i]);
		}
		if(LM == 1) {
			LL ans = 0;	
			rep(i, 1, n) {
				LL tmp = a[i] / sword[i];
				if(sword[i] * tmp < a[i]) ++tmp;
				ans = max(ans, tmp);
			}
			cout << ans << endl;
			continue;
		}
		int flag = 0;
		rep(i, 1, n) {
			LL z = gcd(gcd(a[i], p[i]), sword[i]);
			a[i] /= z; p[i] /= z; sword[i] /= z;
			z = inv(sword[i], p[i]);
			if(z == -1) {
				flag = 1;
				break;
			}
			csf[i][1] = qmul(a[i], z, p[i]);
			csf[i][2] = p[i];
		}
		if(!flag) solve(); else puts("-1");
	}
	return 0;
}
// -O2 
posted @ 2018-10-15 15:48  Qrsikno  阅读(305)  评论(0编辑  收藏  举报