【P1326】超级教主
DP優化
原題:
LHX教主很能跳,因為Orz他的人太多了。教主跳需要消耗能量,每跳1米就會消耗1點能量,如果教主有很多能量就能跳很高。
教主為了收集能量,來到了一個神秘的地方,這個地方凡人是進不來的。在這里,教主的正上方每100米處就有一個能量球(也就是這些能量球位于海拔100,200,300……米處),每個能量球所能提供的能量是不同的,一共有N個能量球(也就是最后一個能量球在N×100米處)。教主為了想收集能量,想跳著吃完所有的能量球。教主可以自由控制他每次跳的高度,接著他跳起把這個高度以下的能量球都吃了,他便能獲得能量球內的能量,接著吃到的能量球消失。教主不會輕功,教主不會二段跳,所以教主不能因新吃到的能量而變化此次跳躍的高度。并且教主還是生活在地球上的,所以教主每次跳完都會掉下來。
問教主若要吃完所有的能量球,最多還能保留多少能量。
N≤2000000?
保證對于所有數據,教主都能吃到所有的能量球,并且能量球包含的能量之和不超過2^31-1。
?
sum[i]表示a[i]的前綴和,很容易推出狀態轉移方程:f[i]=max{j<i && f[j]>=i*100 | f[j]+sum[i]-sum[j]-i*100}
但是數據達到2000000,n^2會T,這是后就要優化
DP優化方法有很多,常用的是記錄可行決策然后二分,單調隊列,斜率優化,我這么弱斜率優化當然不會,這題似乎不符合單調性質,所以我們搞單調隊列
上面的狀態轉移方程↑中sum[i]-i*100是不會變的,需要考慮的就是f[j]-sum[j]
就可以維護單調隊列:如果f[i]>f[隊頭]就進隊,f[j]<i*100的出對,然后在隊里找就行了
然而依舊會T
書上說f[i]-s[i]單調遞減的,過程比較長,有興趣的同學可以試著自己推到(逃
又因為i*100是單調遞增的,所以只需要記錄一個temp表示上一個用到的決策點,從temp往后找到一個f[j]>=i*100就行了
因為f[j]-sum[j]單調遞減且i*100單調遞增,所以如果有f[j]>=i*100的f[j]>=(i-1)*100也肯定滿足,因此從直接從temp開始找就行了,不用管temp前面的
單調性這種東西給數據打個表比較容易發現,優化DP時打個表挺好的
代碼;
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mark; 11 } 12 int n,m,a[2100000]; 13 int sum[2100000]; 14 int f[2100000]; 15 int temp; 16 int main(){//freopen("ddd.in","r",stdin); 17 memset(f,0,sizeof(f)); 18 cin>>n>>m; 19 sum[0]=0; 20 for(int i=1;i<=n;i++){ a[i]=read(); sum[i]=a[i]+sum[i-1];} 21 f[0]=m; temp=0; 22 for(int i=1;i<=n;i++){ 23 for(;temp<i;temp++)if(f[temp]>=i*100) break; 24 f[i]=f[temp]+sum[i]-sum[temp]-i*100; 25 } 26 cout<<f[n]<<endl; 27 return 0; 28 } View Code?
轉載于:https://www.cnblogs.com/JSL2018/p/5861687.html
總結
以上是生活随笔為你收集整理的【P1326】超级教主的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CssVariables_01
- 下一篇: java9-6 内部类