BZOJ1270[BJWC2008]雷濤的小貓
雷濤同學非常的有愛心,在他的宿舍裡,養著一隻因為受傷被救助的小貓(當然,這樣的行為是違反學生宿舍管理條例的)。在他的照顧下,小貓很快恢復了健康,並且愈發的活潑可愛了。
可是有一天,雷濤下課回到寢室,卻發現小貓不見了!經過一番尋找,才發現她正趴在陽臺上對窗外的柿子樹發呆…
在北京大學的校園裡,有許多柿子樹,在雷濤所在的宿舍樓前,就有N棵。並且這N棵柿子樹每棵的高度都是H。冬天的寒冷漸漸籠罩了大地,樹上的葉子漸漸掉光了,只剩下一個個黃澄澄的柿子,看著非常喜人。而雷濤的小貓恰好非常的愛吃柿子,看著窗外樹上的柿子,她十分眼饞,於是決定利用自己敏捷的跳躍能力跳到樹上去吃柿子。
小貓可以從宿舍的陽臺上跳到窗外任意一棵柿子樹的樹頂。之後,她每次都可以在當前位置沿著當前所在的柿子樹向下跳1單位距離。當然,小貓的能力遠不止如此,她還可以在樹之間跳躍。每次她都可以從當前這棵樹跳到另外的任意一棵,在這個過程中,她的高度會下降Delta單位距離。每個時刻,只要她所在的位置有柿子,她就可以吃掉。整個“吃柿子行動”一直到小貓落到地面上為止。
雷濤調查了所有柿子樹上柿子的生長情況。他很想知道,小貓從陽臺出發,最多能吃到多少柿子?他知道寫一個程式可以很容易的解決這個問題,但是他現在懶於寫任何程式碼。於是,現在你的任務就是幫助雷濤寫一個這樣的程式。
圖為N=3,H=10,Delta=2的一個例子。小貓按照圖示路線進行跳躍,可以吃到最多的8個柿子
輸入格式
第一行三個整數N,H,Delta
接下來N行,每行一個整數Ni代表第i個樹上柱子的數量
接下來Ni個整數,每個整數Tij代表第i個樹的高度Tij上有一個柿子
1<=N,H<=2000
0<=Ni<=5000
1<=Delta<=N
1<=Ti<=H
輸入檔案不大於40960Kb
輸出格式
小貓能吃到多少柿子
樣例輸入1
3 10 2
3 1 4 10
6 3 5 9 7 8 9
5 4 5 3 6 9
樣例輸出1
8
題解
非常簡單的DP題,因為過程本身的可逆性,從高處往低處走和從低處往高處走的效果是一樣的。我們設DP[i][j]表示當高度為i時站在第j顆樹上最多可以吃到的果子數量,則如果從高處往低處走的轉移方程很容易可以想到是
\[ dp[i][j]=\begin{cases} dp[i][j]+dp[i+1][j]&i+detal>n\\ max(dp[i][j]+dp[i+1][j],dp[i][j]+max\_note[i+detal]) &i+detal<=n\\ \end{cases} \]
其中$ max_note $記錄每一層果子的最大數量。注意max_note要在DP的過程中持續更新,因為每一層的最大值是隨時都在變動的。
#include<bits/stdc++.h>
using namespace std;
inline char get(){
static char buf[300],*p1=buf,*p2=buf;
return p1==p2 && (p2=(p1=buf)+fread(buf,1,300,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
register char c=get();register int f=1,_=0;
while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
return _*f;
}
int dp[2005][2005];//第一維記高度,第二維記位置
int tot[2005];//記錄總量
int netmax[2005];//當前高度最大值
int n,h,detal;
int main(){
//freopen("1.txt","r",stdin);
n=read();h=read();detal=read();
for(register int i=0;i<2005;i++){
for(register int j=0;j<2005;j++)dp[i][j]=0;
}
for(register int i=1;i<=n;i++){
tot[i]=read();
for(register int j=1;j<=tot[i];j++){
int cas=read();
dp[cas][i]++;
}
}
for(register int i=h;i>=1;i--){//高度
for(register int j=n;j>=1;j--){//樹
if(i+detal<=h)dp[i][j]=max(dp[i][j]+dp[i+1][j],dp[i][j]+netmax[i+detal]);
else dp[i][j]+=dp[i+1][j];
netmax[i]=max(netmax[i],dp[i][j]);
}
}
int out=-1;
for(register int i=1;i<=n;i++)out=max(out,dp[1][i]);
cout<<out;
return 0;
}