[ACGO]挑战赛#6题解

Track 01 :黄金树下的幽影

在一个名为"交界地"的大陆的地下,有着一片被称之为 "幽影之地" 的地方,在这个地方生活着各式各样的原始生物。

现在Yuilice全副武装,拿着心爱的小圆盾和铁剑前往 "幽影之地" 冒险,在冒险之前他需要你来对他的战斗力来进行一次判断,是否有资格前往这片土地冒险。

你使用了一个超级先进的评分系统对于Yuilice的战斗力进行评测,系统告诉了你Yuilice的战斗力为S,同时根据古书上记载,"幽影之地"的最低的生物战斗力为M,而最高的生物战斗力为W。

现在请你给Yuilice最为客观的评价,判定他是否能前往 "幽影之地" 冒险。

输入格式

第一行输入三个整数S,M,W - 代表Yuilice的战斗力与生物最低战斗力与最高战斗力。

输出格式

  • 假如Yuilice完全打不过任何生物,请输出Come back
  • 假如Yuilice的战斗力介于最低生物战斗力与最高生物战斗力之间 (相等也算在之间),请输出You can do it , but be careful
  • 假如Yuilice的战斗力碾压所有生物,请输出Go,now!
  • 输入#1复制

    10 5 10

    输出#1复制

    You can do it , but be careful

    输入#2复制

    10 5 8

    输出#2复制

    Go,now!

    输入#3复制

    2 5 8

    输出#3复制

    Come back
  • 提示说明

    对于100%的数据,1≤S,M,W≤10^{14}

本题是一个签到题,没难度直接上代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long s,m,w;
    cin>>s>>m>>w;
    if(s<m){
        cout<<"Come back";
    }else if(s>=m&&s<=w){
        cout<<"You can do it , but be careful";
    }else{
        cout<<"Go,now!";
    }
    return 0;
}

Track 02:聪明的莫菲特

时间限制:1000ms
空间限制:128mb

Yuilice从黄金树下出发,来到了凯莉尔神树下,通过与神树的接触传送到了幽影之地

Yuilice在传送后来到了一片沼泽,并且身体正在沼泽当中缓缓下沉,焦急的Yuilice四处张望着,发现了一张长着老人脸的石头戏谑的盯着他。

"解开我的谜题,我就放你离开",那块石头如是说着。

谜题内容如下:

给出一个整数n(2≤n≤100),你需要找出一个数x(2≤x≤n)去带入到一个表达式S=x+2x+3x+4x....+kx,kx≤n当中,要求你算出所有x当中,组成最大的S的x的数值为多少?

输入格式

第一行输入一个整数 n。

输出格式

输出一个整数 x - 代表能够组成最大 S 的 x。

样例组

输入#1复制

3

输出#1复制

3

输入#2复制

15

输出#2复制

2

提示说明

对于 n=3 来说, x 的可能值是 2 和 3 。 2 小于或等于 n 的所有倍数之和正好是 2 ,而 3 小于或等于 n 的所有倍数之和是 3 。因此, 3是 x 的最优值。

对于 n=15 , x 的最优值是 2 。 2 小于或等于 n 的所有倍数之和为 2+4+6+8+10+12+14=56 ,可以证明它是 x 所有可能值的最大值。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
  	int n;
    cin>>n;
    int s_max = 0;
    int x_max = 2;
    for(int x=2;x<=n;x++){
        int S = 0;
        for(int k=1;k*x<=n;k++){
            S += k * x;
        }
        if(s_max == 0 || s_max < S){
            s_max = S;
            x_max = x;
        }
    }
    cout<<x_max;
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

「[ACGO]挑战赛#6题解」下半篇开启🔓,欢迎继续观看

---------------------------------------------------------------------------------------------------------------------------------

Track 03:魔剑亚托克斯

题目描述

时间限制:1000ms
空间限制:128mb

挣脱了那块烦人的石头后,Yuilice继续向着幽影之地深处探索。

路上Yuilice在心里暗想,假若能够提升自己的战斗力,也不需要这样小心翼翼了,想到这,Yuilice突然被森林深处的一处魔法阵吸引。

走进观察,原来是一处玄奥的封印魔法阵。在魔法阵的中央,一把巨剑直直的插在地上,剑柄来回撞击着法阵周遭发出"乒乓"的响声。

"凡人,吾名亚托克斯,解开这该死的法阵,待我重获自由后,赋予你强大的力量"

巨剑咆哮着,直直的戳到了Yuilice的心愿。


法阵由无数个玄奥的数字序列所组成,除开那些乱七八糟没有规律的数字序列外,精通魔法阵的Yuilice发觉其中应该会有一段数字序列作为钥匙存在,可以打开魔法阵。

通过仔细观察,Yuilice认为,在一个数字序列当中,如果存在着某个数字可以为其他所有数字之和(如果没有其他数字,那么默认其他数字之和为0),那么该段数字序列就是魔法阵的钥匙。

例如,如果存在数字序列[1,3,5,16,7][1,3,5,16,7],那么这段序列就是其中一把钥匙,因为在这段序列中16=1+3+5+716=1+3+5+7 。

现在Yuilice尽可能找出了有规律的一段数字,长度为𝑛n,Yuilice可以从这段数字当中的第一个数字开始往右取任意连续数字组成一段数字序列。

保险起见,请问Yuilice最多能找出几个满足条件的数字序列作为钥匙?

PS:[0][0]会被视为是一段满足条件的数字序列

输入格式

第一行输入一个整数 𝑛n。

输出格式

输出一个整数 𝑥x - 代表能够组成最大 𝑆S 的 𝑥x。

输入输出样例
  • 输入#1

    复制
    1
    1

    输出#1

    复制
    0
  • 输入#2

    复制
    1
    0

    输出#2

    复制
    1
  • 输入#3

    复制
    5
    0 5 3 2 10

    输出#3

    复制
    3
说明/提示

在第三个测试用例[0,5,3,2,10][0,5,3,2,10]中,共有五个数字序列:

  1. 前缀 [0][0] 满足条件;
  2. 前缀 [0,5][0,5] 不满足条件,因为 0≠50=5 ;
  3. 前缀 [0,5,1][0,5,1] 不满足条件,因为 0≠5+10=5+1 , 1≠5+01=5+0 和 5≠0+15=0+1 ;
  4. 前缀 [0,5,3,2][0,5,3,2] 满足条件,因为 5=3+2+05=3+2+0 ;
  5. 前缀 [0,5,3,2,10][0,5,3,2,10] 满足条件,因为 10=5+3+2+010=5+3+2+0 。

可以看出,其中三个数字序列满足条件,所以答案是 33 。

【数据约定】

对于50%对于50%的数据,1≤𝑛≤103,0≤𝑎𝑖≤1091≤n≤103,0≤ai​≤109

对于100%对于100%的数据,1≤𝑛≤2×105,0≤𝑎𝑖≤1091≤n≤2×105,0≤ai​≤109

存在着某个数字可以为其他所有数字之和,这个数字一定是这个序列的最大值,否则单序列的最大值就会比这个数字大。所以,我们就可以模拟了:首先我们可以 𝑂(𝑛)O(n) 计算数组的前缀和与前缀最大值。接下来判断对于每一个前缀,前缀最大值是否与前缀和减去前缀最大值相等。所有都是 𝑂(𝑛)O(n) 的。

那么AC题解:

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

int a[200005];

inline int read(){
    register int x=0;register char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x;
}

int main(){
	int n;
	scanf("%d",&n);
	for(register int i=1;i<=n;i++) a[i]=read();
	register long long mx=0,sum=0;
	register int cnt=0;
	for(register int i=1;i<=n;i++){
		sum+=a[i];
		if(mx<a[i]) mx=a[i];
		if(sum-mx==mx) cnt++;
	}
	printf("%d",cnt);
	return 0;
}

Track 04:Drogon

题目描述

时间限制:1000ms
空间限制:128mb

Yuilice拔出了魔剑,骑着心爱的骏马"托雷特"在幽影之地的平原上漫无目的奔驰着,一道巨大的黑影一瞬间笼罩了整片平原,Yuilice抬头一看。

一头巨大的黑龙正瞪着它硕大的眼珠凝视着Yuilice,嘴边的尖牙上下摩擦着。

(图片来源于网络)

巨龙自称为飞龙"尖牙",他已经许久没有见到人类了,于是他决定一口火烧掉Yuilice。但是Yuilice手里的魔剑亚托克斯让多雷特感到忌惮,于是他决定与Yuilice玩一个小游戏。


飞龙尖牙口吐魔术火焰,一团团火焰悬浮在了地面上散发着恐怖的热量。

这些火球如果放置不管,会发生巨大的爆炸,将Yuilice炸飞,但是如果能让他们并成一排,那么Yuilice就可以挥动魔剑亚托克斯把他们全部砍碎。

我们可以用一个长度为𝑛n的字符串来表示当时的情景,字符串由.(空地)*(火球)组成,Yuilice可以施展移动魔法将一个火球向左或者向右移动一格。只要所有火球排成一排,Yuilice就可以全部砍碎。

注意!排成一排的定义被视为任何火球之间都不存在着空地!

例如,现在有着一个长度𝑛=6n=6的字符串,并且表示为**.*..,那么可能出现以下场景:

  • 位于 44 位置的火球向右移动,字符串的状态为**..*.
  • 在 22 位置的火球向右移动,字符串的状态为:*.*.*.
  • 位于 11 位置的火球向右移动,字符串的状态为:.**.*.
  • 位于 33 位置的火球向右移动,字符串的状态为.*.**.
  • 在 22 位置的火球向右移动,字符串的状态为:..***.
  • 火球排为一列,Yuilice挥动魔剑砍碎火球,成功幸存。

现在Yuilice为了保存体力对付尖牙,需要使用最少次数的移动魔法保存体力,那么请问他最少需要使用几次移动魔法呢

输入格式

第一行包含一个整数 𝑛n ( 1≤𝑛≤1061≤n≤106 )。

第二行包含一个长度为 𝑛n 的字符串,由字符.(空地)和*(火球)组成--即字符串描述。

输出格式

输出排成一排所需的最少移动次数。

输入输出样例
  • 输入#1

    复制
    6
    **.*..

    输出#1

    复制
    1
  • 输入#2

    复制
    10
    *.*...*.**

    输出#2

    复制
    9
  • 输入#3

    复制
    3
    .*.

    输出#3

    复制
    0
  • 输入#4

    复制
    3
    ...

    输出#4

    复制
    0
说明/提示

对于40%40%的数据,1≤𝑛≤1031≤n≤103

对于100%100%的数据,1≤𝑛≤1061≤n≤106

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N];
long long l[N],r[N];
int main() {
	int n,cnt=0;
	scanf("%d",&n);
	for (int i=1;i<=n;i++) {
		char ch;
		cin>>ch;
		if (ch=='*') {
			a[i]=1;
		}
		cnt+=a[i];
		l[i]=l[i-1];
		if (a[i]==0) {
			l[i]+=cnt;
		}
	}
	cnt=0;
	long long ans=1e18;
	for (int i=n;i>=1;i--) {
		cnt+=a[i];
		r[i]=r[i+1];
		if (a[i]==0) {
			r[i]+=cnt;
		}
		ans=min(ans,l[i-1]+r[i]);
	}
	printf("%lld",ans);
	return 0;
}

Track 05:Kingdom Game II

题目描述

时间限制:5000ms
空间限制 512mb

Yuilice从梦中醒来,发现自己的王国𝑌𝑢𝑖𝑙𝑖𝑐𝑒−𝐾𝑖𝑛𝑔𝐷𝑜𝑚Yuilice−KingDom被敌军入侵了,恼怒的Yuilice打开了O神,呼唤他的军团𝑍ℎ𝑥Zhx复制人军团支援战场。

现在我们可以将战场视为是一个𝑁×𝑁N×N的二维矩阵,由于Yuilice开启了O神,所以他发现地图上共有𝑀M支敌军,并且得知第𝑖i支敌军的位置处于下标为𝑥𝑖xi​与𝑦𝑖yi​的单元格上。

Yuilice一共呼唤了𝐾K支𝑍ℎ𝑥Zhx军团,其中第𝑖i支军团的初始所在地为𝑠𝑥𝑖sxi​与𝑠𝑦𝑖syi​,同时因为传送门太小,导致第𝑖i支军团到达战场的时间为𝑡𝑖ti​秒。

敌军已经被O神的力量吓破了胆,不会移动。𝑍ℎ𝑥Zhx军团在每一秒会划分出四个子军团进行上下左右的移动剿灭敌军,同时被划分出来的子军团还可以继续划分,无穷无尽一直划分下去

𝑍ℎ𝑥Zhx军团神挡杀神佛挡杀佛,所到之处的敌军灰飞烟灭,现在Yuilice困意上头,决定睡个回笼觉,他需要军师--也就是你,算出最少需要几秒才可以消灭所有的敌军?

输入格式

第一行共输入三个整数𝑛,𝑀,𝐾n,M,K - 代表地图大小与敌军军团数量、𝑍ℎ𝑥Zhx军团数量。

随后𝑀M行,每行输入22个整数𝑥𝑖xi​与𝑦𝑖yi​ - 代表第𝑖i支敌军的所在地。

随后𝐾K行,每行输入33个整数𝑠𝑥𝑖、sxi​、𝑠𝑦𝑖syi​与𝑡𝑖ti​ - 代表第𝑖i支𝑍ℎ𝑥Zhx军团的所在地与到达时间。

输出格式

请输出一个整数代表最小需要的秒数。

输入输出样例
  • 输入#1

    复制
    5 2 1
    1 1
    2 2
    3 3 0

    输出#1

    复制
    4
  • 输入#2

    复制
    5 2 2
    1 1
    2 2
    1 1 5
    3 3 0

    输出#2

    复制
    4
  • 输入#3

    复制
    5 2 2
    1 1
    2 2
    1 1 0
    2 2 0

    输出#3

    复制
    0
说明/提示

【样例解释1】

在第00秒时,地图的[3,3][3,3]降临了一支Zhy军团,在第一秒时分出两个子军团前往[3,2][3,2]与[2,3][2,3],在第二秒时候消灭了位于[2,2][2,2]的敌军,在第三秒划分出子军团前往[1,2][1,2]与[2,1][2,1],于第四秒时消灭了位于[1,1][1,1]的敌军。


【样例解释2】

位于[3,3][3,3]降临的军队在第四秒消灭了所有敌军,但是[1,1][1,1]降临的军队还没有落地。


对于50%50%的数据,1≤𝑛≤10,1≤𝑀,𝐾≤𝑛−1,1≤𝑥𝑖,𝑦𝑖,𝑠𝑥𝑖,𝑠𝑦𝑖≤𝑛,0≤𝑡𝑖≤1031≤n≤10,1≤M,K≤n−1,1≤xi​,yi​,sxi​,syi​≤n,0≤ti​≤103

对于100%100%的数据,1≤𝑛≤5×103,1≤𝑀,𝐾≤𝑛−1,1≤𝑥𝑖,𝑦𝑖,𝑠𝑥𝑖,𝑠𝑦𝑖≤𝑛,0≤𝑡𝑖≤1081≤n≤5×103,1≤M,K≤n−1,1≤xi​,yi​,sxi​,syi​≤n,0≤ti​≤108

一种容易想到的方法是广搜。从最早的军团开始搜,到第二个军团的时间了就把第二个军团也加进来一起搜,以此类推。这种做法的时空复杂度都是 𝑂(𝑛2)O(n2) 的,常数还很大,需要有一定的卡常经验才打得好,可惜时限 5s 几乎卡不掉多少。

一种不容易想到的方法是带权曼哈顿距离。我们只需要暴力枚举敌方,计算每一个敌方最早被消灭的时刻。容易发现,被消灭的时刻就是军团到这个敌方的曼哈顿距离+军团到达战场的时间的最小值。所以我们只需要再枚举一下军团就行了。时间复杂度还是 𝑂(𝑛2)O(n2),空间复杂度变为了 𝑂(𝑛)O(n)。然而实际跑起来比广搜快得多,一是因为常数极小 ,二是因为数据过水

做法一代码如下。

———————————————————————————————————————————

若对本文有疑问,可在评论区提出✋↓

本文持续更新

———————————————————————————————————————————

补充:

竞赛说明


本次挑战赛题目难度适中,旨在考察选手对简单算法与思维题的应对能力,相比欢乐赛略有提升。挑战赛的内容涵盖入门级枚举、模拟、二分法、基础数据结构、基础深广搜等内容,主要考察选手对题目的理解能力以及解决常见算法问题的能力。

AC题解:

#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;

#define PRI(x) printf(#x" : %d\n",x)

bool vis[5005][5005];
bool tag[5005][5005];
int dx[]={0,-1,0,1},
    dy[]={-1,0,1,0};
int n,m,k;
struct event{
	int x,y,t;
}e[5005];

inline int read(){
    register int x=0;register char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x;
}

inline bool cmp(event& x,event& y){
	return x.t<y.t;
}
inline bool check(int& x,int& y){
	return x>0&&x<=n&&y>0&&y<=n&&!vis[x][y];
}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(register int i=1;i<=m;i++){
		tag[read()][read()]=1;
	}
	for(register int i=1;i<=k;i++){
		e[i].x=read(),e[i].y=read(),e[i].t=read();
	}
	
	sort(e+1,e+1+k,cmp);
	register int nowi,cnt=2;
	queue<event>q;
	q.push(e[1]);
	vis[e[1].x][e[1].y]=1;
	while(m){
		event f=q.front();
		q.pop();
		if(tag[f.x][f.y]){
			tag[f.x][f.y]=0;
			m--;
		}
		nowi=f.t;
		if(f.t==e[cnt].t){
			while(cnt<=k&&e[cnt].t==f.t) q.push(e[cnt++]);
		}
		for(register int i=0;i<=3;i++){
			int nx=f.x+dx[i],ny=f.y+dy[i];
			if(check(nx,ny)){
				vis[nx][ny]=1;
				q.push({nx,ny,f.t+1});
			}
		}
	}
	printf("%d",nowi);
	
	return 0;
}
#include <cstdio>
#include <algorithm>
#include <memory.h>
using namespace std;

#define pri(x) printf(#x":%d\n",x);

inline int read(){
    register int x=0;register char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x;
}

struct pos1{
	int x,y;
}a[5005];

struct pos2{
	int x,y,t;
}b[5005];

int main(){
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	for(register int i=1;i<=m;i++)
		a[i]={read(),read()};
	
	for(register int i=1;i<=k;i++)
		b[i]={read(),read(),read()};
	
	int ans=0;
	for(register int i=1;i<=m;i++){
		int time=200000000;
		for(register int j=1;j<=k;j++)
			time=min(time,abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)+b[j].t);
		ans=max(ans,time);
	}
	printf("%d\n",ans);
	
	return 0;
}

Track 06:神庙大冒险

题目描述

时间限制:1000ms
空间限制:128mb

Yuilice掉入了一个奇怪的神庙,在这个神庙当中充斥着各种各样的怪物,Yuilice原本还挺怕的,但是看下时间马上要到四点给B班上课了,因此他一下子精神了,准备火速回到柯桥上课。

我们可以把神庙看成是一个𝑁×𝑁N×N的二维矩阵,Yuilice一开始存在着𝑇T点体力值,他只能进行向右或者向下的移动,并且从行为𝑆𝑥Sx​,列为𝑆𝑦Sy​的起点出发。在这个矩阵当中,存在着以下几种情况

  • 字符.代表道路,Yuilice每走一格道路就会损失1点体力值。
  • 字符M代表怪物,Yuilice因为迫切的想要回到B班上课,因此他可以使用𝑘k点体力消灭该格的怪物来到该格当中。(假如起点就有怪物,那么怪物就会被Yuilice降落的余波消灭,不需要消耗体力值)
  • 字符D代表神奇果实,Yuilice可以来到该格吃下果实,补充𝑧z点体力,并且每格的果实只能被食用一次

现在已知终点所处坐标为[𝑁,𝑁][N,N]请你计算出Yuilice回到B班时,他最多还有多少体力值来给B班的同学上课呢?

输入格式

第一行包括六个整数𝑛,𝑇,𝑘,𝑧,𝑆𝑥,𝑆𝑦n,T,k,z,Sx​,Sy​,分别代表地图的大小、初始体力值、消灭怪物的体力值、补充体力值、与起点横坐标与纵坐标。

随后𝑛n行,每行输入𝑛n个字符,代表神庙的地图。

输出格式

输出一个整数代表Yuilice到达B班的最多体力值。

输入输出样例
  • 输入#1

    复制
    3 3 1 100 1 1
    ..M
    ..M
    DM.

    输出#1

    复制
    100
  • 输入#2

    复制
    3 3 1 100 1 1
    DDD
    DDD
    DDD

    输出#2

    复制
    503
  • 输入#3

    复制
    3 3 1 100 1 1
    MMM
    MMM
    MMM

    输出#3

    复制
    -1
说明/提示

【样例解释】

第一组样例:

  • Yuilice由[1,1][1,1]来到[2,1][2,1] 体力值为:2
  • Yuilice由[2,1][2,1]来到[3,1][3,1]吃下了神奇果实 体力值为:102
  • Yuilice由[3,1][3,1]来到[3,2][3,2]消灭了怪物 体力值为:101
  • Yuilice由[3,2][3,2]来到[3,3][3,3] 体力值为:100

第二组样例:

  • Yuilice从落地开始最多走4步到达终点,总计吃5个果实,最后体力值为503

第三组样例:

  • 无论Yuilice如何行走,都要消灭4只怪物,体力值变化为。

  • [1,1],𝑇=3[1,1],T=3

  • [1,2],𝑇=3−𝑧=2[1,2],T=3−z=2

  • [1,3],𝑇=2−𝑧=1[1,3],T=2−z=1

  • [2,3],𝑇=3−𝑧=0[2,3],T=3−z=0

  • [3,3],𝑇=3−𝑧=−1[3,3],T=3−z=−1

  • 最终体力透支为-1

注: 该路线只是多条相同数值的路线的其中一条。

【数据限制】

对于50%50%的数据1≤𝑛≤15,1≤𝑇,𝑘,𝑧≤109,1≤𝑆𝑥,𝑆𝑦≤𝑛1≤n≤15,1≤T,k,z≤109,1≤Sx​,Sy​≤n。

对于100%100%的数据1≤𝑛≤100,1≤𝑇,𝑘,𝑧≤109,1≤𝑆𝑥,𝑆𝑦≤𝑛1≤n≤100,1≤T,k,z≤109,1≤Sx​,Sy​≤n。

题目保证[𝑆𝑥,𝑆𝑦]≠[𝑁,𝑁][Sx​,Sy​]=[N,N]

题意分析

在一个范围为𝑁×𝑁N×N的矩阵当中去求解如何从𝑆𝑥,𝑆𝑦Sx​,Sy​前往终点[𝑁,𝑁][N,N]。 在这个矩阵当中会存在多种情况,一开始价值为𝑇T。

  • 前往的坐标系所指向的类别为. ,价值-1。
  • 前往的坐标系所指向的类别为M,价值-k
  • 前往的坐标系所指向的类别为D,价值+z

针对于起点的类别不同采取

  • 出现D的话进行+z的操作

方向只有右下

算法解析

根据前往的方向可以快速的求得状态和最基本的转移方程

设定𝑑𝑝[𝑖][𝑗]dp[i][j]为到达坐标[𝑖,𝑗][i,j]的最大价值。

到达点𝑑𝑝[𝑖][𝑗]dp[i][j]只能由上和左来到,也就是𝑑𝑝[𝑖][𝑗]=𝑚𝑎𝑥(𝑑𝑝[𝑖−1][𝑗],𝑑𝑝[𝑖][𝑗−1])dp[i][j]=max(dp[i−1][j],dp[i][j−1])

然后,根据地图上的三种情况,MD来对于dp进行累加或者减少。

𝐼𝐹IF 𝑚𝑝[𝑖][𝑗]=.mp[i][j]=. 𝑑𝑝[𝑖][𝑗]=𝑚𝑎𝑥(𝑑𝑝[𝑖−1][𝑗],𝑑𝑝[𝑖][𝑗−1])−1dp[i][j]=max(dp[i−1][j],dp[i][j−1])−1

𝐼𝐹IF 𝑚𝑝[𝑖][𝑗]=𝐷mp[i][j]=D 𝑑𝑝[𝑖][𝑗]=𝑚𝑎𝑥(𝑑𝑝[𝑖−1][𝑗],𝑑𝑝[𝑖][𝑗−1])+𝑧dp[i][j]=max(dp[i−1][j],dp[i][j−1])+z

𝐼𝐹IF 𝑚𝑝[𝑖][𝑗]=𝑀mp[i][j]=M 𝑑𝑝[𝑖][𝑗]=𝑚𝑎𝑥(𝑑𝑝[𝑖−1][𝑗],𝑑𝑝[𝑖][𝑗−1])−𝑘dp[i][j]=max(dp[i−1][j],dp[i][j−1])−k

我们设定𝑑𝑝[𝑆𝑥][𝑆𝑦]dp[Sx​][Sy​]为初始状态,价值一开始为T,但是一旦𝑀𝑝[𝑆𝑥][𝑆𝑦]=𝐷Mp[Sx​][Sy​]=D ,总价值需要加上z进行。

针对于状态转移方程书写代码即可。

时间复杂度分析

最坏需要遍历整个矩阵,所以时间复杂度为𝑂(𝑛2)O(n2)

AC题解:

#include<bits/stdc++.h>
using namespace std;
bool vis[105][105];
long long answer ;
char mp[105][105];
long long dp[105][105];
long long n,t,k,z,sx,sy;
int main()
{
	int n;
	cin >> n >> t >> k >> z >> sx >> sy;
	for(int i = 1 ; i <= n ; i ++ ){
		for(int j = 1 ; j <= n ; j ++ ){
			cin >> mp[i][j];
		}
	} 
	dp[sx][sy] = t;
	if(mp[sx][sy] == 'D')dp[sx][sy] += z;
	for(int i = sx+1 ; i <= n ; i ++ ){
		dp[i][sy] = dp[i-1][sy];
		if(mp[i][sy] == 'D')dp[i][sy] += z;
		if(mp[i][sy] == '.')dp[i][sy] -= 1;
		if(mp[i][sy] == 'M')dp[i][sy] -= k;
	}
	for(int i = sy + 1 ; i <= n ; i ++ )
	{
		dp[sx][i] = dp[sx][i-1];
		if(mp[sx][i] == 'D')dp[sx][i] += z;
		if(mp[sx][i] == '.')dp[sx][i] -= 1;
		if(mp[sx][i] == 'M')dp[sx][i] -= k;
	}
	
	for(int i = sx + 1 ; i <= n ; i ++ )
	{
		for(int j = sy + 1 ; j <= n ; j ++ )
		{
			if(mp[i][j] == 'D')dp[i][j] += z;
			if(i==sx&&j==sy)continue; 
			dp[i][j] += max(dp[i-1][j],dp[i][j-1]);
			if(mp[i][j] == '.')dp[i][j] -= 1;
			if(mp[i][j] == 'M')dp[i][j] -= k;
			
		}
	}
	cout <<dp[n][n] << endl;
	return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

本文借鉴ACGO平台用户发布的题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ysjt | 深

谢谢你!你的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值