CFdiv3-Sending a Sequence Over the Network-(线性dp)

E

题意:
就是说有一个a数组,然后你可以把这个数组分成任意段,然后每段有xi个,那么这个xi要么放在这一段数字的前面或者后面。然后每一段都放好之后,把你分成的这些段数字再合起来形成了b数组。现在给你b数组,问你这个b数组是否可以由某个a数组拆分再合并之后得到来的。

思考:

  1. 当时看到这题,总感觉是暴力?就是贪心选择某个数字是第一段数字的x,但是我发现确定好第一个之后,后面的还是无法确定。所以这个思路不能想了。
  2. 然后我就想,感觉是不是dp呢,然后我就想怎么dp呢?发现也不太好dp,但是我又思考了一会发现,每个点如果作为xi的话就可以代表左边和右边两个区间,所以那么题意就可以转化为:给你一些区间,然后让你选择一些区间是否能正好拼成[1,n]这个区间。同时每个点代表的两个区间也不会同时选,因为中间有个点重合了,所以就转化成了那样的题意。
  3. 那么转化成这个感觉就像一个经典题目了,又和dp联想了一下,感觉想到了之前做的这道题:Cleaning Shifts。区间问题经常用dp去更新,所以就直接按区间的ed排序,然后遍历区间dp转移状态即可。
  4. 反正也是多多思考,多思考一会,多联想联想以前做的题目什么的,去转化题意,把题目往各种可以延申的地方去转化。

代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;

int T,n,m,k;
int va[N];
int dp[N];

vector<PII > v;

bool cmp(PII A,PII B)
{
	return A.se<B.se;
}

signed main()
{
	IOS;
	cin>>T;
	while(T--)
	{
		cin>>n;
		v.clear();dp[0] = 1;
		for(int i=1;i<=n;i++) dp[i] = 0;
		for(int i=1;i<=n;i++)
		{
			cin>>va[i];
			int l = i-va[i],r = i+va[i];
			if(l>=1) v.pb({l,i});
			if(r<=n) v.pb({i,r});
		}
		sort(v.begin(),v.end(),cmp);
		for(auto t:v) dp[t.se] |= dp[t.fi-1];
		dp[n]?cout<<"YES\n":cout<<"NO\n";
	}
	return 0;
}

总结:
多多思考,多多联想。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值