javascript
LuoguP5504 [JSOI2011]柠檬
LuoguP5504 [JSOI2011]檸檬
題目描述
Solution
容易發現一個性質:每一段劃分區間的首尾兩個元素相同。
因為倘若不相同的話其中至少一個元素也就不產生貢獻,將其劃分在其他區間一定不會變劣。
因此就可以寫出一個簡單的O(n2)O(n^2)O(n2)的dpdpdp。
fi=fj?1+(si?sj+1)2(ai=aj)f_i=f_{j-1}+(s_i-s_j+1)^2\;\;\;\;\;\;\;(a_i=a_j) fi?=fj?1?+(si??sj?+1)2(ai?=aj?)
其中sis_isi?表示在iii之前的與iii相同的元素的個數。
考慮決策單調性:
設有j1<j2<ij_1<j_2<ij1?<j2?<i,aj1=aj2a_{j_1}=a_{j_2}aj1??=aj2??,令getans(x,y)getans(x,y)getans(x,y)表示fx?1+(sy?sx+1)2f_{x-1}+(s_y-s_x+1)^2fx?1?+(sy??sx?+1)2。
若getans(j1,i)≥getans(j2,i)getans(j_1,i)\geq getans(j_2,i)getans(j1?,i)≥getans(j2?,i),則對于所有i′≥ii'\geq ii′≥i,都有getans(j1,i′)≥getans(j2,i′)getans(j_1,i')\geq getans(j_2,i')getans(j1?,i′)≥getans(j2?,i′),因為兩者的增長都是平方級別的。
因此我們可以用單調棧維護這一過程。
對于每一種aia_iai?開一個單調棧,我們希望的是保證棧中元素的getans(...,i)getans(...,i)getans(...,i)始終遞增。每次如果發現棧頂元素沒有它下面一個元素優,就彈棧。
但這并不是完全正確的,隨著iii的后移,因為前面的元素增長快,所以可能存在一個j1<j2<j3<ij_1<j_2<j_3<ij1?<j2?<j3?<i,使得getans(j1,i)>getans(j3,i)getans(j_1,i)>getans(j_3,i)getans(j1?,i)>getans(j3?,i),但getans(j2,i)<getans(j3,i)getans(j_2,i)<getans(j_3,i)getans(j2?,i)<getans(j3?,i)。
因此我們還需要保證棧中每一個元素xxx超過上面一個元素yyy的時間小于yyy超過它上面的元素zzz的時間。
這個某個元素超過另一個元素的時間可以二分求得。
所以我們維護單調棧時額外添加一個判斷getans(stack[top?2])>getans(stack[top?1])getans(stack[top-2])>getans(stack[top-1])getans(stack[top?2])>getans(stack[top?1])的時間是否比getans(stack[top?1])>getans(stack[top])getans(stack[top-1])>getans(stack[top])getans(stack[top?1])>getans(stack[top])的時間短即可。
時間復雜度O(nlgn)O(nlgn)O(nlgn)。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <cassert> #include <string.h> //#include <unordered_set> //#include <unordered_map> //#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B) #define PB(A) push_back(A) #define SIZE(A) ((int)A.size()) #define LEN(A) ((int)A.length()) #define FOR(i,a,b) for(int i=(a);i<(b);++i) #define fi first #define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; } template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll; typedef unsigned long long ull; typedef long double lod; typedef pair<int,int> PR; typedef vector<int> VI;const lod eps=1e-11; const lod pi=acos(-1); const int oo=1<<30; const ll loo=1ll<<62; const int mods=998244353; const int MAXN=600005; const int INF=0x3f3f3f3f;//1061109567 /*--------------------------------------------------------------------*/ inline int read() {int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } ll f[MAXN]; vector<int> V[MAXN]; int a[MAXN],s[MAXN],cnt[MAXN],n; ll Getans(int x,int y) { return f[x-1]+1ll*a[x]*y*y; } ll getans(int x,int y) { return f[x-1]+1ll*a[x]*(s[y]-s[x]+1)*(s[y]-s[x]+1); } int check(int x,int y) {int l=s[y],r=n+1;while (l<r){int mid=(l+r)>>1;if (Getans(x,mid-s[x]+1)>=Getans(y,mid-s[y]+1)) r=mid;else l=mid+1;}return r; } int main() {n=read();for (int i=1;i<=n;i++) s[i]=++cnt[a[i]=read()];f[0]=0;for (int i=1,sz;i<=n;i++){sz=V[a[i]].size()-1;while (sz>=1&&check(V[a[i]][sz-1],V[a[i]][sz])<=check(V[a[i]][sz],i)) V[a[i]].pop_back(),sz--;V[a[i]].PB(i),sz++;while (sz>=1&&getans(V[a[i]][sz-1],i)>=getans(V[a[i]][sz],i)) V[a[i]].pop_back(),sz--;f[i]=getans(V[a[i]][sz],i);}printf("%lld\n",f[n]);return 0; }總結
以上是生活随笔為你收集整理的LuoguP5504 [JSOI2011]柠檬的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经常流鼻血还头痛是怎么回事?
- 下一篇: LuoguP5366 [SNOI2017