题意:
一段a序列,划分他,每一个区间都有一个长度,这个长度可以放在他划分的区间的左侧或者右侧,然后重新构成一个b序列,现在给出b序列,问能否由a序列得来
思路:
首先,去暴力分析,划分的区间数有超复杂度种情况,所以肯定不能去暴力的划分区间,其次,每个区间都是一个一个长度,一段序列, 信息只有这么多了,观察一下,首端和尾端,发现首端的状态,很难判断,但是尾端的状态是很好判断的,尾端的那个状态,最后一个数字,要么是左侧的区间长度,要么是由前面的某个状态得来的,这里有一个转移,可以思考dp了,如果dp[i - b[i] - 1] = true, 说明这个状态是可以的,dp[i] = true, 然后如果不能从这个状态转移过来,那就说明,只能由前面的某一长度转移过来了,初始化dp[0] = true, 因为最后一个状态是肯定只有这两种状态,然后dp转移的过程中已经枚举了所有的情况,所以这个dp是可行的
总结:
如果暴力分析感觉超时间复杂度,可以分解,注意题目给出的条件,观察题目的首尾极端条件即可,线性dp, dp枚举了所以的划分状态
点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 10;
ll T, n;
ll b[MAXN];
bool dp[MAXN];
void init()
{
for (int i = 1; i <= n; ++i)
dp[i] = false;
}
int main()
{
IOS; cin.tie(0), cout.tie(0);
cin >> T;
while (T--)
{
cin >> n;
init();
for (int i = 1; i <= n; ++i)
cin >> b[i];
dp[0] = true, dp[1] = false;
for (int i = 1; i <= n; ++i)
{
if (i + b[i] <= n && dp[i - 1]) //作为右侧的长度,而且还没有越界
dp[i + b[i]] = true;
if (i - b[i] - 1 >= 0 && dp[i - b[i] - 1]) //作为左侧的长度,而且还没有越界
dp[i] = true;
}
cout << (dp[n] ? "YES" : "NO") << endl;
}
return 0;
}
/*
1
2
1 1
*/