CF 933 A  Twisty Movement

博客解析了CF933A问题,涉及序列翻转和最长不下降子序列的求解。博主分享了从错误的前缀、后缀递推思路转向正确解法的过程,并推荐了一篇相关博客链接。

题目链接 https://www.luogu.org/problemnew/show/CF933A
题目描述:
给定一个序列 A,你可以翻转其中的一个区间内的数,求翻转后的序列的最长不下降子序列的长度。(题目给的数字只有1和2)

题目分析:
考虑一下怎么做这道题,本蒟一开始看到这题的时候,想到的是前缀、后缀之类的。然后觉得要去递推一下,搞两重循环,一重为i,一重为j准备用f[i]表示前i个数字经过交换之后能够得到的最长不下降子序列的长度。但后来又想该怎么去找这个翻转,想了一会儿后发现走不通。后来在网上找了找博客,发现了一个解释,现讲一下做法。(代码中讲解吧)

#include <cstdio> 
#include <cmath> 
#include <queue> 
#include <cstring> 
#include <algorithm> 
using namespace std; 
#define mst(a,b) memset((a),(b),sizeof(a)) 
#define rush() int T; scanf("%d",&T); while(T--) 
typedef long long ll; 
const int maxn = 2005; 
const ll mod = 1e9+7; 
const ll INF = 1e18+5; 
const double eps = 1e-9; 
int n; int a[maxn]; 
int pre1[maxn]; 
int pre2[maxn]; 
int main() {
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d",&n); 
	for(int i=1;i<=n;i++) { 
		scanf("%d",&a[i]); 
		pre1[i]=pre1[i-1]+(a[i]==1);//pre1[]表示的是i位置前有多少个1 
	} 
	for(int i=n;i>=1;i--) pre2[i]=pre2[i+1]+(a[i]==2);//pre2[]表示i位置后有多少个2 
	int ans=0; 
	//对于l,计算[1,l-1]中1的个数和[l,pos]中2的个数和的最大值。
	//对于r,计算[r,n]中2的个数和[pos,r-1]中1的个数和的最大值。
	for(int k=1;k<=n+1;k++) { 
		int num1=0,num2=0; //枚举位置pos 
		for(int i=1;i<=k;i++) 
			num1=max(num1,pre1[i-1]+pre2[i]-pre2[k]); //枚举l*我们枚举一下左端点。
		pre1[i-1]表示1到i-1有多少个1
		pre2[i]-pre2[k]表示的是i到k有多少个2
		*/
		for(int i=k;i<=n+1;i++) 
			num2=max(num2,pre2[i]+pre1[i-1]-pre1[k-1]); //枚举r *
		pre2[i]表示i到n有多少个2
		pre1[i-1]-pre1[k-1]表示i-1到k-1有多少个1
		*/*
		然后我们再来看一看上述两个循环是不是将整个区间分成了四段?
		就第一个循环来看分成的是1到l和l+1到k,第二个循环来看分成的是k到r和r+1到n
		然后我们看这里得到了l+1到k的2的个数,然后也得到了k到r的1的个数
		那按照题目来看是不是把这个一翻转就可以得到答案了?
		那个num1记录的就是1到l的1的个数和l+1到k的2个数
		而num2记录的就是k到r中1的个数和r+1到n的2的个数
		最后相加是不是就得到了答案?取个max即可。(不得不佩服那位博主QWQ)
		*/
		ans=max(ans,num1+num2); 
	}		 
	printf("%d\n",ans); 
	return 0;
}

应该算讲清楚了吧。
附上链接:https://blog.youkuaiyun.com/acm513828825/article/details/79467850

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值