题意:沙滩从左往右由海岸线,n米的海和一个在n+1的点的岛组成。一个人测量了从海岸线\(1,2,\dots,n\)米到岛屿的海的深度,并保存在\(d\)数组中,这个海有潮汐,潮汐的强度取决于参数\(k\),参数\(k\)影响了海的深度,对于从时间\(t = 0\)开始,先k秒,每一秒,潮汐导致所有的深度+1,然后再k秒,潮汐每秒导致所有的深度都减1。这个过程不断地持续着,例如对于索引从0开始的数组\(p = [0, 1, 2,...,k - 2, k - 1, k, k - 1, k - 2, ..., 2, 1]\),长度为2k,在时间t,第i米的深度为\(di+p[t\,mod\,k]\)。这个人从海岸线开始游到岛屿,每一秒,他可以前进或者呆在原地,时间t + 1,这个人有一个被淹死的水的深度的参数\(l\),如果\(当且深度>l\),那么这个人就会被淹死。求是否存在一种游的方式,使得这个人可以游到岛屿。

分析:可以看到\(n\)只有100,题目中每次游动的方式又只有两种,可以想到用搜索做。在比赛的时候,我定义的状态是\(位置和时间\),这样不能有效地检测出不能游到海岸的方案。因为我很难判断两个状态是否是一致的,如果对于当且状态来说,之前出现过一个一样的状态,那么说明,经过了时间2 * k,还在当前点,说明状态的转移之间出现了环,因此这个搜索的分支是返回false的。官方题解里用位置,潮汐导致的增量,潮汐是在上升还在下降定义状态,然后用一个set存储之前出现过的状态,如果在set里面发现了一个和当且状态一样的状态,那么就说明过了时间2 * k,还是当且的状态,返回false。然后,在搜索的时候,我们有两种方式游,一种是呆在原地即d[pos] + tide <= l && dfs(pos, tide, down),另一种是向下一个位置游动d[pos + 1] + tide <= l && dfs(pos + 1, tide, down)。当然,还有两个小细节,比如d[0]和d[n + 1]表示海岸线和岛屿的深度,这个直接赋值一个很小的负数即可,只要能游过去即可。还有潮汐导致的深度变换应该是\(1, 2, ..., k, k - 1, k - 2, ..., 0\),因为p数组中当t是k的倍数的时候,会直接模到0,容易混淆。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <tuple>
#include <algorithm>

using namespace std;
const int N = 105;
int d[N];

struct Node
{
	int pos, tide;
	bool down;
	bool operator<(const Node& rhs)const
	{
		if (pos != rhs.pos)
			return pos < rhs.pos;
		else
		{
			if (tide != rhs.tide)
				return tide < rhs.tide;
			else
				return down < rhs.down;
		}
	}
};
int n, k, l;
set<Node> v;
bool dfs(int pos, int tide, bool down)
{
	//游到岛屿
	if (pos > n) return true;
	//集合中是否存在一个和当且状态一样的状态
	if (v.find({ pos, tide, down }) != v.end()) return false;
	//插入到set中
	v.insert({ pos, tide, down });

	tide += down ? -1 : +1;
	if (tide == 0) down = false;
	if (tide == k) down = true;

	if (d[pos] + tide <= l && dfs(pos, tide, down))
		return true;
	if (d[pos + 1] + tide <= l && dfs(pos + 1, tide, down))
		return true;
	return false;
}

int main()
{
	int t;
	scanf("%d", &t);

	while (t--)
	{
		scanf("%d%d%d", &n, &k, &l);
		for (int i = 1; i <= n; ++i)
			scanf("%d", &d[i]);
		d[0] = d[n + 1] = -k;

		if (dfs(0, 0, false))
			puts("Yes");
		else
			puts("No");
		v.clear();
		//memset(d, 0, sizeof d);
	}


	return 0;
}