题目
题解
和裸的线段覆盖差不多,但是我数组开小了还是没能1A。dp[ i ][ j ]表示覆盖到i的长度,用了j的代价获得的最大快乐值。先把物品按右端点排序之后,依次扫描有没有可以用来转移的物品。也就是说如果存在一个物品m使得m.x+m.len==i(右端点在i),那么:
dp[ i ][ j ]=max(dp[ i ][ j ],dp[ m.x ][ j-m.cost ]+m.val );
(注意dp时两个for和一个while的顺序)因为强制要求覆盖满,所以初始状态只能是dp[ 0 ][ 0 ]=0, 别的都为-1,也是因为这个所以答案不一定是dp[m][C](m是长度,C是最大的代价),需要扫一遍。
代码
//QWsin
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxl=1000+10;
const int maxn=10000+10;
const int maxm=1000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
struct equip{
int x,len,val,cost;
bool operator < (const equip &rhs)const{
return x+len<rhs.x+rhs.len;
}
inline void input(){
x=read();len=read();val=read();cost=read();
}
}a[maxn];
int dp[maxl][maxm];
int main()
{
freopen("std.in","r",stdin);
int m,n,C;cin>>m>>n>>C;
for(int i=1;i<=n;i++) a[i].input();
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
sort(a+1,a+n+1);
int p=0;
for(int i=1;i<=n;i++)
while(p+1<=n&&a[p+1].x+a[p+1].len==i)
{
p++;
for(int j=C;j>=a[p].cost;j--)
if(dp[a[p].x][j-a[p].cost]!=-1)
dp[i][j]=max(dp[i][j],dp[a[p].x][j-a[p].cost]+a[p].val);
}
int ans=-1;
for(int j=1;j<=C;j++) ans=max(ans,dp[m][j]);
printf("%d\n",ans);
return 0;
}