摘橘子
Time Limit:20000MS Memory Limit:65536K
Total Submit:1 Accepted:1
Case Time Limit:1000MS
Description
约翰在农场上种了一排共N棵橘子树,约翰将它们编号1到N。又到了橘子成熟的季节,约翰安排他的M头奶牛去摘橘子。但每头奶牛都有自己独特的采摘习惯:
第i头奶牛最多只愿意摘连续Xi棵橘子树上的橘子,并且其中要包括它最喜欢的第Zi号橘子树(它也可以一棵树都不摘)。
第i头奶牛每摘一棵树,都会从该树上摘下恰好Yi个橘子(每棵树上的橘子都足够多)。
奶牛不愿采摘其它牛摘过的树,所以一棵树最多只能被一只牛采摘。
约翰想知道,怎样安排采摘工作才能使得摘下的橘子总数尽可能多。
Input
第一行,两个整数N和M,表示橘子的数量和奶牛的数量
接下来M行,每行代表一头奶牛,其中第i行的三个整数Xi, Yi, Zi,描述i号奶牛的采摘习惯
Output
一行,一个整数,表示最多能摘下的橘子总数
Sample Input
样例输入1:
8 4
3 2 2
3 2 3
3 3 5
1 1 7
样例输入2:
1 2
13 11 1
1 15 1
Sample Output
样例输出1:
17
样例输出2:
15
Hint
对于50%的数据: 1<=M<=100 1<=N<=1000 1<= Yi<=10000 1<=Xi<=N
对于100%的数据: 1<=M<=100 1<=N<=30000 1<= Yi<=10000 1<=Xi<=N
样例1说明:
1号奶牛采摘第1到2棵树
2号奶牛采摘第3到4棵树
3号奶牛采摘第5到7棵树
4号奶牛不采摘。
Source
改编自POJ1821
z为喜欢的树的编号
x为工作最大长度
y为各自收益
用f[i][j]表示前i只奶牛处理前j个树的最大收益
因此有三种决策:
1.不用第i头奶牛,即f[i][j]=f[i-1][j]
2.不用第j棵树,f[i][j]=f[i][j-1]
3.前i-1只处理k棵,第i只处理第k+1到j棵,状态转移方程为:f[i][j]=max(f[i-1][k]+y[i]*(j-k)) k<z&&k>=j-x
容易得出50分的暴力dp代码:
#include<iostream>
#include<cstdio>
#include<deque>
#include<algorithm>
using namespace std;
struct node{int L,P,S;}Cow[105];
int dp[105][16005];
deque<int>Q;
bool cmp(node a,node b){return a.S<b.S;}
int main(){
int i,j,k,n,m,tmp,Left,Right;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d%d%d",&Cow[i].L,&Cow[i].P,&Cow[i].S);
sort(Cow+1,Cow+m+1,cmp);
for(i=1;i<=m;i++){
Left=max(0,Cow[i].S-Cow[i].L);
Right=min(n,Cow[i].S+Cow[i].L-1);
for(j=0;j<Cow[i].S;j++)dp[i][j]=dp[i-1][j];
for(j=Cow[i].S;j<=Right;j++){
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
for(k=Left;k<Cow[i].S;k++)
if(k>=j-Cow[i].L)dp[i][j]=max(dp[i][j],dp[i-1][k]+(j-k)*Cow[i].P);
}
for(j=Right+1;j<=n;j++)dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
printf("%d\n",dp[m][n]);
}
因此,j*y[i]是相对固定的,因此在一个区间上求f[i-1][k]-y[i]*k的最大值,应该用单调队列的滑动窗口模型
#include<iostream>
#include<cstdio>
#include<deque>
#include<algorithm>
using namespace std;
struct wk{int x,y,z;}s[105];
int f[105][16005];
deque<int>q;
bool cmp(wk a,wk b){return a.z<b.z;}
int main(){
int i,j,k,n,m,tmp,l,r;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].z);
sort(s+1,s+m+1,cmp);
for(i=1;i<=m;i++){
l=max(0,s[i].z-s[i].x);
r=min(n,s[i].z+s[i].x-1);
for(j=0;j<s[i].z;j++)
f[i][j]=f[i-1][j];
q.clear();
for(k=l;k<s[i].z;k++){
tmp=f[i-1][k]-k*s[i].y;
while(!q.empty()&&f[i-1][q.back()]-q.back()*s[i].y<tmp)q.pop_back();
q.push_back(k);
}
for(j=s[i].z;j<=r;j++){
while(!q.empty()&&j-q.front()>s[i].x)q.pop_front();
f[i][j]=max(f[i-1][j],f[i][j-1]);
f[i][j]=max(f[i][j],f[i-1][q.front()]+(j-q.front())*s[i].y);
}
for(j=r+1;j<=n;j++)
f[i][j]=max(f[i-1][j],f[i][j-1]);
}
printf("%d",f[m][n]);
}