[solution] Luogu-P4774 [NOI2018] Dragon Slayer

If you fight with a dragon for too long, you will become a dragon. If you stare at the abyss too long, the abyss will stare back.

-- Nietzsche's the other side of good and evil

P4774 [NOI2018] Dragon Slayer

Description \text{Description} Description

Players need to be numbered 1 → n 1 \to n Kill in 1 → n order n n n dragons. Each dragon has an initial health value b i b_i bi​. At the same time, each dragon has the ability to recover, which will increase its health every time a i a_i ai until the health value is non negative.

At the beginning of the game, the player has m m m swords. Each sword has an attack power a t k i atk_i atki, every time you face the dragon, the player can only choose one sword. When you kill the dragon, the sword will disappear, but the player will get a new sword.

Each time when facing the dragon, the player will choose the sword with the greatest attack power not higher than the dragon's initial HP as the weapon. If there is no such sword, choose the sword with the lowest attack power as the weapon.

In the face of each dragon, players will attack the dragon with the sword of their choice x x x times( x x x is a constant), which reduces the dragon's health x ⋅ a t k x \cdot atk x⋅atk.

After that, the dragon will continue to use the recovery ability every time a i a_i ai) health. If the health value before or after a recovery is 0 0 0, the Dragon dies and the player passes the customs.

Now give all the attributes of each dragon and request the number of attacks that should be made by the robot x x x is set to how many times to use the least number of attacks to pass the game.

If you can't pass the game no matter how many settings are set, output − 1 -1 −1.

Solution \text{Solution} Solution

The sword whose attack power is not higher than the dragon's initial HP is the most powerful weapon

Directly use the balance tree or m u l t i s e t \rm multiset multiset can be realized. We set the attack power of this sword as c o e i coe_i coei​.

Then make the HP equal to 0 0 0 is actually the smallest nonnegative integer x x x. Make
{ c o e 1 ⋅ x ≡ b 1 ( m o d a 1 ) c o e 2 ⋅ x ≡ b 2 ( m o d a 2 ) ⋯ c o e n ⋅ x ≡ b n ( m o d a n ) \begin{cases} coe_1\cdot x\equiv b_1\pmod {a_1}\\ coe_2\cdot x\equiv b_2\pmod {a_2}\\ \cdots\\ coe_n\cdot x\equiv b_n\pmod {a_n} \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧​coe1​⋅x≡b1​(moda1​)coe2​⋅x≡b2​(moda2​)⋯coen​⋅x≡bn​(modan​)​
For such a congruence equation c o e ⋅ x ≡ b ( m o d a ) coe\cdot x\equiv b\pmod a coe ⋅ x ≡ b(moda), direct use e x g c d \rm exgcd exgcd converts it to x ≡ b ′ ( m o d a gcd ⁡ ( c o e , a ) ) x\equiv b'\pmod{\frac{a}{\gcd(coe,a)}} x ≡ b '(modgcd(coe,a)a).

Note that the modulus must be divided by gcd ⁡ ( c o e , a ) \gcd(coe,a) gcd(coe,a), otherwise it will leak. (this little Ao should have said all about it)

Then there is a e x C R T \rm exCRT exCRT.

Note: the blood volume of each dragon must be negative before it can start to return blood, so a variable is used during processing m n mn mn records at least how many attacks to attack, m n = max ⁡ { ⌊ b i a t k i ⌋ } mn=\max\left\{\left\lfloor\dfrac{b_i}{atk_i}\right\rfloor\right\} mn=max {⌊ atki ⌋ bi ⌋}, and then the solution x x x plus one lcm ⁡ ( a 1 , a 2 , ... , a n ) \operatorname{lcm}(a_1,a_2,\dots,a_n) The multiple of lcm(a1, a2,..., an) makes x ≥ m n x\ge mn x ≥ mn.

That's what made me adjust 5 5 5 days and let me do this problem 6 6 All six people doubt life

Code \text{Code} Code

//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cstring>
#define Debug(x) cout << #x << "=" << x << endl
typedef long long ll;
using namespace std;

const int MAXN = 1e5 + 5;

ll a[MAXN], b[MAXN], coe[MAXN];

namespace Math
{
	ll div_ceil(ll x, ll y)
	{
		return (x - 1) / y + 1;
	}
	
	ll x, y;
	
	ll exgcd(ll a, ll b)
	{
		if (!b)
		{
			x = 1, y = 0;
			return a;
		}
		ll Gcd = exgcd(b, a % b);
		ll tmp = x;
		x = y;
		y = tmp - a / b * y;
		return Gcd;
	}
	
	ll qmul(ll a, ll b, ll p)
	{
		if (b < 0)
		{
			a = -a;
			b = -b;
		}
		ll base = a, ans = 0;
		while (b)
		{
			if (b & 1)
			{
				ans = (ans + base) % p;
			}
			base = (base + base) % p;
			b >>= 1;
		}
		return (ans + p) % p;
	}
	
	int pre(int n)
	{
		for (int i = 1; i <= n; i++)
		{
			ll Gcd = exgcd(coe[i], a[i]);
			if (b[i] % Gcd)
			{
				return -1;
			}
			a[i] /= Gcd; // Be sure to divide the modulus first
			b[i] /= Gcd;
			b[i] = (qmul(x, b[i], a[i]) + a[i]) % a[i]; // Re mold
		}
		return 1;
	}
	
	ll A, B;
	
	int merge(ll a, ll b)
	{
		ll Gcd = exgcd(A, a), c = B - b;
		if (c % Gcd)
		{
			return -1;
		}
		c /= Gcd;
		x = (qmul(x, c, a) + a) % a;
		ll Lcm = A / Gcd * a;
		B = (B - qmul(A, x, Lcm) + Lcm) % Lcm;
		A = Lcm;
		return 1;
	}
	
	ll exCRT(int n, ll mn)
	{
		if (pre(n) == -1)
		{
			return -1;
		}
		A = a[1], B = b[1];
		for (int i = 2; i <= n; i++)
		{
			if (merge(a[i], b[i]) == -1)
			{
				return -1;
			}
		}
		if (B < mn)
		{
			B += div_ceil(mn - B, A) * A;
		}
		return B;
	}
}
using Math::div_ceil;
using Math::exCRT;

namespace BST
{
	int tot, rt;
	
	struct treap
	{
		int lson, rson;
		ll val;
		int key;
	}t[MAXN << 1];
	
	void init()
	{
		tot = rt = 0;
		memset(t, 0, sizeof(t));
	}
	
	int build(ll val)
	{
		t[++tot] = treap{0, 0, val, rand()};
		return tot;
	}
	
	void split(int pos, ll val, int &a, int &b)
	{
		if (!pos)
		{
			a = b = 0;
			return;
		}
		if (t[pos].val <= val)
		{
			a = pos;
			split(t[pos].rson, val, t[a].rson, b);
		}
		else
		{
			b = pos;
			split(t[pos].lson, val, a, t[b].lson);
		}
	}
	
	int merge(int a, int b)
	{
		if (!a || !b)
		{
			return a + b;
		}
		if (t[a].key > t[b].key)
		{
			t[a].rson = merge(t[a].rson, b);
			return a;
		}
		else
		{
			t[b].lson = merge(a, t[b].lson);
			return b;
		}
	}
	
	void insert(ll val)
	{
		int a = 0, b = 0, c = build(val);
		split(rt, val, a, b);
		rt = merge(merge(a, c), b);
	}
	
	void remove(ll val)
	{
		int a = 0, b = 0, c = 0;
		split(rt, val, a, b);
		split(a, val - 1, a, c);
		c = merge(t[c].lson, t[c].rson);
		rt = merge(merge(a, c), b);
	}
	
	ll getpre(ll val) // Maximum number less than or equal to val
	{
		int a = 0, b = 0;
		split(rt, val, a, b);
		int pos = a;
		while (t[pos].rson)
		{
			pos = t[pos].rson;
		}
		rt = merge(a, b);
		return t[pos].val;
	}
	
	ll getmin()
	{
		int pos = rt;
		while (t[pos].lson)
		{
			pos = t[pos].lson;
		}
		return t[pos].val;
	}
}
using BST::init;
using BST::insert;
using BST::remove;
using BST::getpre;
using BST::getmin;

int n, m;
ll mn;
ll atk[MAXN], rew[MAXN];

void read()
{
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld", b + i);
	}
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld", a + i);
	}
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld", rew + i);
	}
	for (int i = 1; i <= m; i++)
	{
		scanf("%lld", atk + i);
	}
}

void cal()
{
	init();
	for (int i = 1; i <= m; i++)
	{
		insert(atk[i]);
	}
	mn = 0;
	for (int i = 1; i <= n; i++)
	{
		ll res = getpre(b[i]);
		if (res)
		{
			coe[i] = res;
		}
		else
		{
			coe[i] = getmin();
		}
		mn = max(mn, div_ceil(b[i], coe[i]));
		remove(coe[i]);
		insert(rew[i]);
	}
}

int main()
{
//	freopen("dragon.in", "r", stdin);
//	freopen("dragon.out", "w", stdout);
	srand((unsigned)time(NULL));
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		read();
		cal();
		printf("%lld\n", exCRT(n, mn));
	}
	return 0;
}

After fighting with the Dragon slaying warrior for a long time, he also became the Dragon slaying warrior, that is, the dragon.

Tags: data structure Math

Posted on Fri, 03 Dec 2021 09:41:15 -0500 by wint.thaw