1. 程式人生 > >JZOJ-senior-1773. 【NOIP動態規劃專題】猴子

JZOJ-senior-1773. 【NOIP動態規劃專題】猴子

Time Limits: 1000 ms Memory Limits: 65536 KB

Description

一個猴子找到了很多香蕉樹,這些香蕉樹都種在同一直線上,而猴子則在這排香蕉樹的第一棵樹上。這個猴子當然想吃盡量多的香蕉,但它又不想在地上走,而只想從一棵樹跳到另一棵樹上。同時猴子的體力也有限,它不能一次跳得太遠或跳的次數太多。每當他跳到一棵樹上,它就會把那棵樹上的香蕉都吃了。那麼它最多能吃多少個香蕉呢?

Input

輸入第一行為三個整數,分別是香蕉樹的棵數N,猴子每次跳躍的最大距離D,最多跳躍次數M。   下面N行每行包含兩個整數,ai,bi,分別表示每棵香蕉樹上的香蕉數,以及這棵樹到猴子所在樹的距離。輸入保證這些樹按照從近到遠排列,並且沒有兩棵樹在同一位置。b0總是為0。

Output

輸出只有一行,包含一個整數,為猴子最多能吃到的香蕉數。

Sample Input

5 5 2 6 0 8 3 4 5 6 7 9 10

Sample Output

20

Data Constraint

ai<=10000,D<=10000 100%的資料有M<N<=2000,bi<=10000

Solution

  • 顯然DP,設 f i
    , j f_{i,j}
    表示跳了 i i 次,到達第 j
    j
    棵樹上的能吃到的最多的香蕉數
  • 那麼 f i , j = m a x ( f i 1 , k + a [ j ] f_{i,j}=max({f_{i-1,k}+a[j]} )(b[j]-b[k]<=D)
  • 乍一看, O ( n 3 ) O(n^3) ,於是考慮優化DP
  • 容易發現,對於跳同樣步數的決策 j , k ( j &lt; k ) j,k(j&lt;k)
  • 要是決策 k k 不僅能吃到更多的香蕉,而且能到達更遠的位置,那麼決策 j j 就沒有了意義
  • 於是我們用單調佇列優化即可

Code

#include<algorithm>
#include<cstdio>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)

using namespace std;

const int N=2010;
int n,m,k,ans;
int a[N],d[N],q[N],f[N][N];

int main()
{
	freopen("monkey.in","r",stdin);
	freopen("monkey.out","w",stdout);
	scanf("%d%d%d",&n,&k,&m);
	fo(i,1,n) scanf("%d%d",&a[i],&d[i]);
	f[0][1]=a[1];
	fo(i,1,m)
	{
		int l=1,r=0;
		fo(j,i+1,n)
		{
			while(r>=l&&f[i-1][j-1]>=f[i-1][q[r]]) --r;
			q[++r]=j-1;
			while(d[j]-d[q[l]]>k) ++l;
			f[i][j]=f[i-1][q[l]]+a[j];
			ans=max(ans,f[i][j]);
		}
	}
	printf("%d",ans);
}