列表

详情


NC21120. [NOI2018]屠龙勇士

描述

小 D 最近在网上发现了一款小游戏。游戏的规则如下: 
• 游戏的目标是按照编号 1~n 顺序杀掉 n 条巨龙,每条巨龙拥有一个初始的生命 值 ai 。
同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每 次增加 pi ,直至生命值非负。只有在攻. 击. 结. 束. 后. 且当生命值恰. 好. 为 0 时它才会 死去。
• 游戏开始时玩家拥有 m 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一 把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。 小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格, 于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:
• 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻. 击. 力. 最. 大. 的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作 为武器。 
• 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的x 次,使 巨龙的生命值减少 x × AT K 。 
• 之后,巨龙会不断使用恢复能力,每次恢复 pi 生命值。若在使用恢复能力前或 某一次恢复后其生命值为 0 ,则巨龙死亡,玩家通过本关。
 那么显然机器人的攻击次数是决定能否最快通关这款游戏的关键。
小 D 现在得知 了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数 x 设置为多少, 才能用最少的攻击次数通关游戏吗? 
当然如果无论设置成多少都无法通关游戏,输出-1 即可。

输入描述

第一行一个整数 T ,代表数据组数。
接下来 T 组数据,每组数据包含 5 行。
• 每组数据的第一行包含两个整数,n 和 m ,代表巨龙的数量和初始剑的数量;
• 接下来一行包含 n 个正整数,第 i 个数表示第 i 条巨龙的初始生命值 ai;
• 接下来一行包含 n 个正整数,第 i 个数表示第 i 条巨龙的恢复能力 pi
• 接下来一行包含 n 个正整数,第 i 个数表示杀死第 i 条巨龙后奖励的剑的攻击力;
• 接下来一行包含 m 个正整数,表示初始拥有的 m 把剑的攻击力。

输出描述

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

示例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

说明:

第一组数据:
• 开始时拥有的剑的攻击力为 {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。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1380ms, 内存消耗: 9948K, 提交时间: 2019-05-30 19:34:54

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100000+10;
int n,m,flag;ll a[maxn],p[maxn],b[maxn],c[maxn],A[maxn],B[maxn],Max;
multiset<ll> s;
multiset<ll>::iterator it;

void exgcd(ll a,ll b,ll &g,ll &x,ll &y){
    if(b==0){
        g=a;x=1;y=0;
        return;
    }
    exgcd(b,a%b,g,y,x);
    y-=(a/b)*x;
}

inline ll mul(ll a,ll b,ll mod){
    ll ret=0;b=(b%mod+mod)%mod;
    for(;b;b>>=1,a=(a+a)%mod)
        if(b&1) ret=(ret+a)%mod;
    return ret;
}

inline void merge(ll &a1,ll &b1,ll a2,ll b2){
    ll d=a2-a1,g,x,y;
    exgcd(b1,b2,g,x,y);
    if(d%g==0){
        x=(mul(x,d/g,b2/g)+(b2/g))%(b2/g);
        a1=x*b1+a1;b1=b1/g*b2;
    }
    else flag=1;
}

inline ll excrt(ll *a,ll *b){
    ll a1,b1,a2,b2;
    a1=a[1];b1=b[1];
    for(int i=2;i<=n;i++){
        a2=a[i];b2=b[i];
        merge(a1,b1,a2,b2);
        if(flag) return -1;
    }
    if(a1>=Max) return a1;
    return a1+((Max-a1)/b1+((Max-a1)%b1?1:0))*b1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);flag=Max=0;s.clear();
        ll d,g,x,y;
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
        for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
        for(int i=1;i<=m;i++){
            scanf("%lld",&x);
            s.insert(x);
        }
        for(int i=1;i<=n;i++){
            it=s.upper_bound(a[i]);
            if(it!=s.begin()) it--;
            c[i]=*it;s.erase(s.find(*it));s.insert(b[i]);
            Max=max(Max,a[i]/c[i]+(a[i]%c[i]?1:0));
        }

        for(int i=1;i<=n;i++){
            d=a[i];exgcd(c[i],p[i],g,x,y);
            if(d%g){flag=1;break;}
            x=(mul(x,d/g,p[i]/g)+(p[i]/g))%(p[i]/g);
            A[i]=x;B[i]=p[i]/g;
        }
        if(flag) printf("-1\n");
        else printf("%lld\n",excrt(A,B));
    }
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 606ms, 内存消耗: 8284K, 提交时间: 2023-07-16 16:11:10

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
long long r[N];
long long m[N];
long long q[N];
long long at[N];
int n,k;
long long gcd(long long a,long long b)
{
	return b?gcd(b,a%b):a;
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
	long long x1,y1,d;
	d=exgcd(b,a%b,x1,y1);
	x=y1;
	y=x1-a/b*y1;
	return d;
}
long long lcm(long long a,long long b)
{
	return a/gcd(a,b)*b;
}
int tp;
long long mx=0;
long long CRT()
{
	tp=n;
	long long ans=0,M=1,A,B,C,x,y;
	for(int i=1;i<=tp;i++)
	{
		A=(__int128)at[i]*M%m[i];
		B=m[i];
		C=(r[i]-at[i]*ans%m[i]+m[i])%m[i];
		long long d=exgcd(A,B,x,y);
		if(C%d) return -1;
		x=(x%B+B)%B;
		ans+=(__int128)(C/d)*x%(B/d)*M%(M*=B/d);
		ans%=M;
	}
	if(ans<mx) ans=((mx-1)/M+1)*M;
	return ans;
}
void solve()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>r[i];
	}
	for(int i=1;i<=n;i++)
	{
		cin>>m[i];
	}
	for(int i=1;i<=n;i++)
	{
		cin>>q[i];
	}
	multiset<long long>s;
	for(int i=1;i<=k;i++)
	{
		long long x;
		cin>>x;
		s.insert(x);
	}
	mx=0;
	for(int i=1;i<=n;i++)
	{
		multiset<long long>::iterator it=s.upper_bound(r[i]);
		if(it!=s.begin()) it--;
		at[i]=*it;
		s.erase(it);
		s.insert(q[i]);
		mx=max(mx,(r[i]-1)/at[i]+1);
	}
	cout<<CRT()<<'\n';
}

int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

上一题