1. 程式人生 > 實用技巧 >CF1038D Slime(思維+列舉+貪心)(來自洛谷)

CF1038D Slime(思維+列舉+貪心)(來自洛谷)

洛谷地址:https://www.luogu.com.cn/problem/CF1038D

題意:

n只史萊姆,每一個史萊姆可以吃相鄰的左或右,它的分數就變成:它的分數-被吃的分數

求最大的剩餘值。

解析:

如果對過程進行太多的分析的話,問題就會變得很複雜。剛開始想的是,把所有能算出來的負數弄出來,但是情況又有好多,接著又想到dp....越想越多。

這個時候,嘗試分情況討論,簡化具體過程,這是一個教訓!

1:正負均有,要想結果最大,肯定是讓負數儘可能多,然後讓正數去減它。

假設有x個正數,讓負數把x-1的正數全變成負數,讓最後的那個正數去減所有負數,得到的結果就是所有數的絕對值之和。

既然正負均有,那麼肯定存在正負相鄰,所以這個結論是正確的。

2:全為正

參照一,如果弄出一個負數來,那麼結果也跟絕對值有關,就是:去掉它倆的剩餘數的絕對值之和+它倆吃出的價值(取正,因為吃左吃右都可以)

這個時候就可以O(N)列舉相鄰數了。

全為負同理。

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<string.h>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=5e5+10
; ll a[maxn]; ll b[maxn]; int vis[maxn]; int main() { int n; cin>>n; int tot=0; int z=0,f=0; ll sum=0; for(int i=1;i<=n;i++) { cin>>a[i]; sum+=abs(a[i]); if(a[i]>0) z++; if(a[i]<0) f++; } if(n==1
) cout<<a[1]<<endl; else if(z>0&&f>0) { cout<<sum<<endl; } else { ll ans=0; for(int i=2;i<=n;i++) { ans=max(ans,sum-abs(a[i])-abs(a[i-1])+abs(a[i]-a[i-1])); } cout<<ans<<endl; } }