題目鏈接:http://codeforces.com/problemset/problem/789/C
題目大意:對於N個數,選定其中的【L,R】的數,
使得|a[l+1]-a[l]|-|a[l+2]-a[l+3]|+….+|a[r-1]-a[r-2]|-|a[r]-a[r-1]|最大;
其實就是每兩個數做差,得到一個n-1長度的序列b,然後對序列b的【L,R】區間裏,從L開始數第一項以及後面的奇數項都是加,第二項以及後面的偶數項都是減。在這樣的條件下求出最大值。
思路:分成兩種情況,對於新構造的序列b,一種是選擇的區間裏,L是奇數,另一種就是L是偶數了。
不難看出,如果選擇的L是奇數,那麼在進行累加的時候,偶數項都應該是減掉,也就是隻要對序列b的偶數項都乘上一個-1之後,用一維DP的思路求最大連續子序列和(Max Sum ,詳情參考hdu1003),得出一個最大值,然後把奇數項乘上-1,偶數項變回原狀,再求一次Max Sum,取兩者之間的較大值即可。
簡單說下hdu1003,也就是最大連續子序列和;
用dp的思路將,dp【i】應該是保存【1,i】這個區間裏,以i爲結尾的最大連續子序列和;
而對於dp【i+1】來說,如果dp【i】>0,那麼dp[i+1]=dp[i]+a[i+1];否則,dp[i+1]=a[i+1];因爲前綴比0小,加上反而會變少。然後可以發現,每次DP的過程,並不需要用到之前的dp[i-2]的數據,所以連數組都不用開,直接用一個變量sum記錄一個累加和,一旦sum小於0就從0開始繼續累加就好。
注意:數據爆int,需要longlong
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL absi(LL n)
{
if(n<0)
return -n;
return n;
}
LL road[100005];
int main()
{
int n;
cin>>n;
for(int i=0 ; i<n ; i++)
{
cin>>road[i];
}
LL maxi=0;
LL save=0;
for(int i=1 ; i<n ; i++)
{
road[i-1]=absi(road[i-1]-road[i]);
maxi=max(road[i-1],maxi);
}
for(int i=0 ; i<n-1 ; i++)
{
if(i%2!=0)
road[i]*=-1;
}
for(int i=0 ; i<n-1 ; i++)
{
save+=road[i];
if(save<0)
{
save=0;
}
maxi=max(maxi,save);
}
for(int i=0 ; i<n-1 ; i++)
{
road[i]*=-1;
}
save=0;
for(int i=0 ; i<n-1 ; i++)
{
save+=road[i];
if(save<0)
{
save=0;
}
maxi=max(maxi,save);
}
cout<<maxi<<endl;
return 0;
}