6310. Global warming

6310. Global warming 
(File IO): input:glo.in output:glo.out

Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits  

Description

给定整数 n 和 x,以及一个大小为 n 的序列 a。
你可以选择一个区间 [l,r],然后令 a[i]+=d(l<=i<=r),其中 d 满足 |d|<=x。
要求最大化 a 的最长上升子序列的长度,并输出该值

Input

第一行输入包含两个整数 n 和 x。
接下来一行 n 个整数表示序列 a。

Output

输出只有一行,包含一个整数,a 的最长上升子序列的最大值。

Sample Input

8 10
7 3 5 12 2 7 3 4
 

Sample Output

5
 

Data Constraint

对于 5% 的数据点,n,x<=10;
对于另外 10% 的数据点,n,x<=50;
对于另外 13% 的数据点,n<=1000;
对于另外 10% 的数据点,x=0;
对于另外 20% 的数据点,x<=5,n<=50000;
对于另外 17% 的数据点,x=10^9;
对于 100% 的数据点,n<=200000,x<=10^9。

Source / Author: CEOI2018 day1 glo

 

题解:

一个显然的结论 , 加值肯定在后缀加,减值肯定在前缀减是最优的。

还有 , 加上一个值就要加的透彻 , 直接加x就行了,减同理。

又发现 , 前缀减 , 等价于后缀加。

所以我们只需枚举分界点i , 让后面的加x看看LIS为多少。

 

我们先倒着做求出g[i]表示以n~i最长下降子序列长度。

然后求f[i]。

f[i]表示i为分界点(从i开始加x)的答案。

最后ans = max(ans , f[i] + g[i] - 1)

为什么是对?因为f[i]表示i为分界点(从i开始加x)的答案 , 那么对于n~i的每个位置都加了个x , 加完之后g[i]大小还是不变的。

减去一是因为i位衔接起来选了两次。

f的求法根平常一样 , 只不过f[i]!=lower_bound(d+1 , d+1+len+1 , a[i])-d , 而是为 lower_bound(d+1 , d+1+len+1 , a[i]+x)-d。

#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof(a))
#define N 200010
#define ll long long
#define re register
#define inf 2147483647
#define mod (ll)(1e9+7)
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;

template 
T in(T &x)
{
	char ch(0);T f=0; x=0;
	while(ch < '0' || ch > '9') ch = getchar() , f |= ch == '-';
	while(ch>='0' && ch<='9')  x = (x<<1) + (x<<3) + ch - '0' , ch = getchar();
	return f ? (x = -x) : x;
}


int n,x;
int a[N], len,d[N],ans,f[N],g[N];

int main()
{
	open("glo");
	in(n) , in(x);
	for(int i=1;i<=n;i++) in(a[i]);
	for(int i=1;i<=n;i++)
	{
		d[len+1] = inf;
		f[i] = lower_bound(d+1 , d+1+len+1 , a[i]+x)-d;
		*lower_bound(d+1,d+1+len+1,a[i]) = a[i];
		len = d[len+1] ? len+1 : len;
	}
	mem(d,0);
	for(int i=n;i>0;--i)
	{
		g[i] = lower_bound(d+1 , d+1+len+1 , a[i] , greater())-d;
		*lower_bound(d+1,d+1+len+1,a[i],greater()) = a[i];
		len = d[len+1] ? len+1 : len;
	}
	for(int i=1;i<=n;i++) ans = max(ans , f[i] + g[i] - 1);
	printf("%d\n",ans);
	return 0;
		
}

 

 

 

 

 

你可能感兴趣的:(dp,结论题)