Topic link:
bzoj2726
Luogu 2365
It seems that O(n2)O(n^2)O(n2) can pass on Luogu. There's no negative number yet...
If there is no negative number, the direct optimization of Dali's upper slope is based on qwq.
The transfer equation is DP [i]=dp [i]=dp [i] = DP [i] [j]+sumT [i]][i]+sumT [i]]] [i] [i]] [c[i]] [c[n]\[c [j]][c [j]][dp [i]+sumT [i]]* (c[i]-c[i]-c]-c [j]]]]]-c [j]]]]]-dp [i]]] [i]]] [i]]] [i]]] [dp [i] [i] [i]]==dp [dp [i] [i] [[dp [j]]]]c[j] (sumT,csumT,csumT,c denotes prefix and)
Here is the code of Logu AC, bzojWA:
#include<stdio.h> #include<cstring> #include<algorithm> #include<math.h> #include<vector> #define re register int #define rl register ll using namespace std; typedef long long ll; ll read() { rl x=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9') { x=10*x+ch-'0'; ch=getchar(); } return x*f; } namespace I_Love { const int Size=50005; const int LOG=20; int n,s,T[Size],F[Size],Queue[Size]; int sumt[Size],c[Size],dp[Size]; inline double X(int i) { return c[i]; } inline double Y(int i) { return dp[i]; } inline double slope(int i,int j) { return (Y(j)-Y(i))/(X(j)-X(i)); } void Fujibayashi_Ryou() { n=read(); s=read(); for(re i=1; i<=n; i++) { T[i]=read(); F[i]=read(); sumt[i]=sumt[i-1]+T[i]; c[i]=c[i-1]+F[i]; } int hd=1,tl=1; Queue[tl]=0; for(re i=1; i<=n; i++) { while(hd<tl && slope(Queue[hd],Queue[hd+1])<=sumt[i]+s) hd++; dp[i]=dp[Queue[hd]]+sumt[i]*(c[i]-c[Queue[hd]])+s*(c[n]-c[Queue[hd]]); while(hd<tl && slope(Queue[tl-1],Queue[tl])>=slope(Queue[tl],i)) tl--; Queue[++tl]=i; } printf("%d",dp[n]); } } int main() { I_Love::Fujibayashi_Ryou(); return 0; }
Then consider the negative energy of T, FT, FT and F.
TTT and FFF can cause T,FT,FT,F prefix and non-monotonous.
For this non-monotonous case, Ke sets a cdqcdqcdq divide and conquer:
The essence of cdqcdqcdq divide and conquer is to solve left and right intervals, and then push right intervals with left intervals.
Firstly, the solution of the iii DPDP value is regarded as an operation.
To solve the prefix and non-monotonous situation of TTT, TTT is regarded as the first dimension of cdqcdq division and conquer, first according to the prefix and ranking of TTT.
After sorting, Ke ensures the prefix and order of TTT. Consider how to push from left to right.
If l=rl=rl=r, there is only one operation in the current interval. qwq can be built for this operation.
For the interval [l,r][l,r][l,r], put the original number & lt; = mid< = mid <= mid in [l,mid][l,mid][l,mid] [r] [mid + 1, r] [mid + 1, r], and then solve [l,mid][l,mid][l,mid].
At this time, the original number of [l,mid][l,mid][l,mid] interval is smaller than the original number of [mid+1,r][mid+1,r][mid+1,r], while the prefix and sum of TTT are monotonous, so Coe optimizes qwq with Dali slope.
Attention should be paid to the right interval of the left interval first, and then recursively solve the right interval. Otherwise, when l=rl=rl=r, the DPDP value of this location has not been calculated, it will stink qwq.
Cancer Code
#include<stdio.h> #include<cstring> #include<algorithm> #include<math.h> #define re register int #define rl register ll using namespace std; typedef long long ll; ll read() { rl x=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9') { x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } return x*f; } const int Size=500005; const int INF=0x3f3f3f3f; ll n,S,F[Size],T[Size],dp[Size]; struct node { double x,y; int id; } w[Size],tmp[Size]; inline bool comp(node mhy,node zwt) { return T[mhy.id]<T[zwt.id]; } inline bool operator < (node mhy,node zwt) { if(mhy.x!=zwt.x) return mhy.x<zwt.x; return mhy.y<zwt.y; } void Divide(int l,int r) { //divide [l,r] into [l,mid] & [mid+1,r] //id<=mid -> [l,mid] //id>mid -> [mid+1,r] int mid=(l+r)>>1; int ptr1=l,ptr2=mid+1; for(re i=l; i<=r; i++) { if(w[i].id<=mid) { tmp[ptr1++]=w[i]; } else { tmp[ptr2++]=w[i]; } } for(re i=l; i<=r; i++) { w[i]=tmp[i]; } } node Queue[Size]; inline double slope(node A,node B) { return (B.y-A.y)/(B.x-A.x); } void CDQ_Divide(int l,int r) { if(l==r) { //l=r is the construction point w[l].x=F[w[l].id]; w[l].y=dp[w[l].id]; return; } int mid=(l+r)>>1; //Divide the interval into [l,mid] and [mid+1,r] according to the original number id. //The process of partition does not affect the monotonicity qwq of the prefix sum of T Divide(l,r); CDQ_Divide(l,mid); //Slope optimization, first left to right, then recursive solution to the right int hd=1,tl=0; for(re i=l; i<=mid; i++) { while(hd<tl && slope(Queue[tl-1],Queue[tl])>slope(Queue[tl-1],w[i])) tl--; Queue[++tl]=w[i]; } for(re i=mid+1; i<=r; i++) { while(hd<tl && slope(Queue[hd],Queue[hd+1])<S+T[w[i].id]) hd++; int j=Queue[hd].id; dp[w[i].id]=min(dp[w[i].id],dp[j]+S*(F[n]-F[j])+T[w[i].id]*(F[w[i].id]-F[j])); } CDQ_Divide(mid+1,r); } int main() { // freopen("data.txt","r",stdin); // freopen("WA.txt","w",stdout); memset(dp,0x3f,sizeof(dp)); n=read(); S=read(); for(re i=1; i<=n; i++) { //T,F denotes prefix and T[i]=T[i-1]+read(); F[i]=F[i-1]+read(); w[i].id=i; } sort(w+1,w+1+n,comp); //This initialization is very grand. dp[0]=0; CDQ_Divide(0,n); printf("%lld",dp[n]); return 0; }