zoukankan      html  css  js  c++  java
  • 「NOI2018」屠龙勇士

    题目描述

    小 D 最近在网上发现了一款小游戏。游戏的规则如下:

    • 游戏的目标是按照编号 (1 ightarrow n) 顺序杀掉 (n) 条巨龙,每条巨龙拥有一个初始的生命值 (a_i)​ 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 (p_i) ,直至生命值非负。只有在攻击结束后且当生命值恰好(0) 时它才会死去。

    • 游戏开始时玩家拥有 (m) 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。

    小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格,于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:

    • 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作为武器。

    • 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 (x) 次,使巨龙的生命值减少 (x imes ATK)

    • 之后,巨龙会不断使用恢复能力,每次恢复 (p_i)​ 生命值。若在使用恢复能力前或某一次恢复后其生命值为 (0) ,则巨龙死亡,玩家通过本关。

    那么显然机器人的攻击次数是决定能否最快通关这款游戏的关键。小 D 现在得知了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数 (x) 设置为多少,才能用最少的攻击次数通关游戏吗?

    当然如果无论设置成多少都无法通关游戏,输出 (-1) 即可。

    输入格式

    第一行一个整数 (T),代表数据组数。

    接下来 (T) 组数据,每组数据包含 (5) 行。

    • 每组数据的第一行包含两个整数,(n)(m),代表巨龙的数量和初始剑的数量;

    • 接下来一行包含 (n) 个正整数,第 (i) 个数表示第 (i) 条巨龙的初始生命值 (a_i)

    • 接下来一行包含 (n) 个正整数,第 (i) 个数表示第 (i) 条巨龙的恢复能力 (p_i)

    • 接下来一行包含 (n) 个正整数,第 (i) 个数表示杀死第 (i) 条巨龙后奖励的剑的攻击力;

    • 接下来一行包含 (m) 个正整数,表示初始拥有的 (m) 把剑的攻击力。

    输出格式

    一共 (T) 行。

    (i) 行一个整数,表示对于第 (i) 组数据,能够使得机器人通关游戏的最小攻击次数 (x),如果答案不存在,输出 (-1)

    输入输出样例

    输入

    2
    3 3
    3 5 7
    4 6 10
    7 3 9
    1 9 1000
    3 2
    3 5 6
    4 8 7
    1 1 1
    1 1
    

    输出

    59
    -1
    

    说明/提示

    更多样例

    更多样例请在附加文件中下载。

    样例 2

    见附加文件中的 dragon2.indragon2.ans

    样例 1 解释

    第一组数据:

    • 开始时拥有的剑的攻击力为 ({1,9,10}),第 (1) 条龙生命值为 (3),故选择攻击力为 (1) 的剑,攻击 (59) 次,造成 (59) 点伤害,此时龙的生命值为 (-56),恢复 (14) 次后生命值恰好为 (0),死亡。

    • 攻击力为 (1) 的剑消失,拾取一把攻击力为 (7) 的剑,此时拥有的剑的攻击力为 ({7,9,10}),第 (2) 条龙生命值为 (5),故选择攻击力为 (7) 的剑,攻击 (59) 次,造成 (413) 点伤害,此时龙的生命值为 (-408),恢复 (68) 次后生命值恰好为 (0),死亡。

    • 此时拥有的剑的攻击力为 ({3,9,10}),第 (3) 条龙生命值为 (7),故选择攻击力为 (3) 的剑,攻击 (59) 次,造成 (177) 点伤害,此时龙的生命值为 (-170),恢复 (17) 次后生命值恰好为 (0),死亡。

    • 没有比 (59) 次更少的通关方法,故答案为 (59)

    第二组数据:

    • 不存在既能杀死第一条龙又能杀死第二条龙的方法,故无法通关,输出 (-1)

    子任务

    测试点编号 (n) (m) (p_i) (a_i) 攻击力 其他限制
    1 (le 10^5) (=1) (=1) (le 10^5) (=1)
    2 (le 10^5) (=1) (=1) (le 10^5) (=1)
    3 (le 10^5) (=1) (=1) (le 10^5) (le 10^5)
    4 (le 10^5) (=1) (=1) (le 10^5) (le 10^5)
    5 (le 10^3) (le 10^3) (le 10^5) (le 10^5) (le 10^5) 特性 1、特性 2
    6 (le 10^3) (le 10^3) (le 10^5) (le 10^5) (le 10^5) 特性 1、特性 2
    7 (le 10^3) (le 10^3) (le 10^5) (le 10^5) (le 10^5) 特性 1、特性 2
    8 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    9 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    10 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    11 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    12 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    13 (=1) (=1) (le 10^8) (le 10^8) (le 10^6) 特性 1
    14 (=10^5) (=10^5) (=1) (le 10^8) (le 10^6) 无特殊限制
    15 (=10^5) (=10^5) (=1) (le 10^8) (le 10^6) 无特殊限制
    16 (le 10^5) (le 10^5) 所有 (p_i) 是质数 (le 10^{12}) (le 10^6) 特性 1
    17 (le 10^5) (le 10^5) 所有 (p_i)​是质数 (le 10^{12}) (le 10^6) 特性 1
    18 (le 10^5) (le 10^5) 无特殊限制 (le 10^{12}) (le 10^6) 特性 1
    19 (le 10^5) (le 10^5) 无特殊限制 (le 10^{12}) (le 10^6) 特性 1
    20 (le 10^5) (le 10^5) 无特殊限制 (le 10^{12}) (le 10^6) 特性 1

    特性 1 是指:对于任意的 (i)(a_i le p_i)

    特性 2 是指:(operatorname{lcm}(p_i) le 10^6),即所有 (p_i)最小公倍数不大于 (10^6)

    对于所有的测试点,(T le 5),所有武器的攻击力 (le 10^6),所有 (p_i)​ 的最小公倍数 (le 10^{12})

    保证 (T, n, m) 均为正整数。

    提示

    你所用到的中间结果可能很大,注意保存中间结果的变量类型。

    附件下载

    dragon.zip 1.60MB

    题解

    首先很容易将题意转化为

    给定若干个如下式的不定方程,解出最小解 (x)

    [ATK_i imes xequiv a_i mod p_i ]

    对于单个不定方程,我们可以化简一下

    为什么化简?

    如果 (gcd (ATK_i,p_i) eq 1),会发现,可以解出 (gcd (ATK_i,p_i)) 个解使得这个不定方程成立

    但是我们最后要求解的是一个不定方程组,无法得知取那个解是正确的,所以两边同除 (gcd (ATK_i,p_i)),使得不定方程解出一个解,从而利于不定方程组的求解

    然后用 (ExGCD) 来求解,化成若干个同余方程的形式,最后 (ExCRT) 合并一下就好了

    但是上述做法并不能处理 (p_i=1) 的情况,所以要特判一下,其实就是 (max {frac{a_i}{ATK_i}}),注意上取整

    作为 (NOI; 2018) 的签到题,还是挺水的吧

    代码
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    
    typedef long long ll;
    typedef unsigned long long ull;
    
    using namespace std;
    
    const int maxn = 1e5 + 50, INF = 0x3f3f3f3f;
    
    inline ll read () {
    	register ll x = 0, w = 1;
    	register char ch = getchar ();
    	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    inline void write (register int x) {
    	if (x / 10) write (x / 10);
    	putchar (x % 10 + '0');
    }
    
    int T, n, m;
    bool ALLONE = 1;
    vector <int> vec;
    ll maxx, a[maxn], b[maxn], c[maxn], p[maxn], atk[maxn];
    
    inline ll Mul (register ll a, register ll b, register ll mod) {
    	register ll tmp = (long double) a / mod * b, res = (ull) a * b - (ull) tmp * mod;
    	return (res % mod + mod) % mod;
    }
    
    inline ll ExGCD (register ll a, register ll b, register ll &x, register ll &y) {
    	if (! b) return x = 1, y = 0, a;
    	register ll d = ExGCD (b, a % b, x, y), tmp = x;
    	return x = y, y = tmp - a / b * y, d;
    }
    
    inline ll ExCRT () {
    	register ll ans = c[1], lcm = p[1], maxx = 0;
    	for (register int i = 2; i <= n; i ++) {
    		register ll res = ((c[i] - ans) % p[i] + p[i]) % p[i], x = 0, y = 0, gcd = ExGCD (lcm, p[i], x, y), tmp = p[i] / gcd;
    		if (res % gcd) return -1;
    		x = Mul (x, res / gcd, tmp), ans += x * lcm, lcm *= tmp, ans = (ans % lcm + lcm) % lcm, maxx = max (maxx, p[i]);
    	} 
    	return (ans % lcm + lcm) % lcm;
    }
    
    int main () {
    	T = read();
    	while (T --) {
    		n = read(), m = read(), vec.clear (), ALLONE = 1, maxx = 0;
    		for (register int i = 1; i <= n; i ++) a[i] = read();
    		for (register int i = 1; i <= n; i ++) {
    			p[i] = read();
    			if (p[i] != 1) ALLONE = 0;
    		}
    		for (register int i = 1; i <= n; i ++) atk[i] = read();
    		for (register int i = 1; i <= m; i ++) vec.push_back (read ());
    		sort (vec.begin (), vec.end ());
    		for (register int i = 1, res; i <= n; i ++) {
    			res = upper_bound (vec.begin (), vec.end (), a[i]) - vec.begin ();
    			if (res) res --;
    			b[i] = vec[res], vec.erase (vec.begin () + res);
    			res = lower_bound (vec.begin (), vec.end (), atk[i]) - vec.begin ();
    			vec.insert (vec.begin () + res, atk[i]);
    		}
    		if (ALLONE) {
    			for (register int i = 1; i <= n; i ++) maxx = max (maxx, (ll) ceil (1.0 * a[i] / b[i]));
    			printf ("%lld
    ", maxx);
    		} else {
    			for (register int i = 1; i <= n; i ++) {
    				register ll x = 0, y = 0, res = ExGCD (b[i], p[i], x, y);
    				x = 0, y = 0, res = ExGCD (res, a[i], x, y), b[i] /= res, p[i] /= res, a[i] /= res, x = 0, y = 0;
    				register ll gcd = ExGCD (b[i], p[i], x, y), tmp = p[i] / gcd;
    				if (a[i] % gcd) { puts ("-1"); goto end; }
    				else x = (x % tmp + tmp) % tmp, c[i] = Mul (x, a[i] / gcd, tmp);
    			}
    			printf ("%lld
    ", ExCRT ()); end:;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    pickle模块使用
    Graphviz安装教程
    Redis常用命令
    MongoDB和Redis的区别
    UVA-1572
    poj2352
    poj1195
    Codeforces Round #430 (Div. 2)
    Codeforces Round #431 (Div. 2) B. Tell Your World
    poj3278 【BFS】
  • 原文地址:https://www.cnblogs.com/Rubyonly233/p/14296086.html
Copyright © 2011-2022 走看看