1. 程式人生 > 其它 >CodeForces 1691D (單調棧 區間最值/最大子區間和)

CodeForces 1691D (單調棧 區間最值/最大子區間和)

題意: 判斷陣列是否滿足所有子陣列滿足:

  • 列舉最值,一個最值所控制的區間是左邊和右邊第一個比他大的數的位置的開區間。
  • 用這個區間的最大子區間和和最值比較
  • 最大子區間和可以用i到R-1的最大值減去L到i-1的最小值得到,也可以像大嘴貓吃金幣那樣求。
    http://acm.zzuli.edu.cn/problem.php?id=2892
#include<bits/stdc++.h>
//#include <bits/extc++.h>
using namespace std;
// using namespace __gnu_cxx;
// using namespace __gnu_pbds;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);  
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define ull unsigned long long
#define li __int128_t
//#define int long long
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const int mod = 998244353;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
ll a[N], pre[N], L[N], R[N];
ll f[N][30], F[N][30]; int n;
void ST_create(){
 for(int i=1;i<=n;i++){
   f[i][0]=pre[i];
 }
 int k=log2(n);
 for(int j=1;j<=k;j++){
   for(int i=0;i<=n-(1<<j)+1;i++){ // 注意從零開始
     f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
   }
 }
}
void ST_create1(){
 for(int i=1;i<=n;i++){
   F[i][0]=pre[i];
 }
 int k=log2(n);
 for(int j=1;j<=k;j++){
   for(int i=0;i<=n-(1<<j)+1;i++){
     F[i][j]=min(F[i][j-1],F[i+(1<<(j-1))][j-1]);
   }
 }
}
ll mx(int l,int r){
 int k=log2(r-l+1);
 return max(f[l][k],f[r-(1<<k)+1][k]);
}
ll mn(int l,int r){
 if( r == 0 ) return 0;
 int k=log2(r-l+1);
 return min(F[l][k],F[r-(1<<k)+1][k]);
}
void solve() {
 cin >> n;
 for ( int i = 1; i <= n; ++ i ) {
   cin >> a[i]; pre[i] = pre[i - 1] + a[i];
 }
 stack<int> st;
 for ( int i = 1; i <= n; ++ i ) {
   while( st.size() && a[st.top()] <= a[i] ) st.pop();
   if(st.size()) L[i] = st.top(); else L[i] = 0;
   st.push(i); 
 }
 while( st.size() ) st.pop();
 for ( int i = n; i >= 1; -- i ) {
   while( st.size() && a[st.top()] <= a[i] ) st.pop();
   if(st.size()) R[i] = st.top(); else R[i] = n + 1;
   st.push(i); 
 }
 ST_create(); ST_create1();

 for ( int i = 1; i <= n; ++ i ) {
   int r1 = R[i] - 1;
   int l1 = L[i];
   int de1 = mx( i, r1);
   if( mx( i, r1) - mn( l1, i - 1) > a[i] ) {
     cout << "NO" << '\n'; return;
   }
 }
 cout << "YES" << '\n';
 for ( int i = 1; i <= n; ++ i ) pre[i] = 0;
}
int main() {
 int t; cin >> t;
 while( t -- ) solve();
 return 0;
}