将挂钩数从大到小排序,然后f[ i ] [ j ]表示前i个装饰剩余j个钩子的最大价值,转移十分简单
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
char ch=getchar();int f=0,x=1;
while(ch<'0'||ch>'9'){if(ch=='-') x=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){f=(f<<1)+(f<<3)+ch-'0';ch=getchar();}
return f*x;
}
int f[2005][4005],n,a[2005],b[2005];
struct data
{
int a;
int b;
}q[2005];
bool cmp(const data &a,const data &b)
{
return a.a>b.a;
}
int main()
{
memset(f,-0x7f7f7f7f,sizeof(f));
n=read();
for(int i=0;i<=n;i++)
{
for(int j=0;j<=2*n;j++)
f[i][j]=-2100000000;
}f[0][1]=0;
for(int i=1;i<=n;i++)
{
q[i].a=read();q[i].b=read();
}sort(q+1,q+n+1,cmp);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=2*n;j++)
{
if(j)
{
f[i][min(j+q[i].a-1,2*n)]=max(f[i-1][j]+q[i].b,f[i][min(j+q[i].a-1,2*n)]);
f[i][j]=max(f[i][j],f[i-1][j]);
}
else
{
f[i][j]=max(f[i][j],f[i-1][j]);
}
}
}
int ans=0;
for(int i=0;i<=2*n;i++)
ans=max(ans,f[n][i]);
cout<<ans;
}