少见的DP再DP题目。题面不短,但是可以看出来这是一道DP题。而且正解的算法复杂度应该是$O(N^3)$。而且给了部分$O(N^4)$的算法的分。可以看出来要AC是要在DP上加上优化的。
设$g[i][j]$表示$[i,j]$内满足条件的最大答案贡献,这个用背包可以很轻松的处理出来。然后再设$f[i][k]$表示前$i$个分$k$组的最大答案。可以得到如下状态转移
$f[i][k]=max\{ f[j-1][k-1]+g[j][i] \}$
把背包上的枚举优化掉一维就行了。
代码实现上也存在诸多细节。
1 //OJ 1312 2 //by Cydiater 3 //2016.10.6 4 #include <iostream> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <queue> 9 #include <map> 10 #include <ctime> 11 #include <iomanip> 12 #include <cstdlib> 13 #include <cstdio> 14 #include <cmath> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 #define pii pair<int,int> 20 #define fi first 21 #define se second 22 const int MAXN=1e3+5; 23 const int oo=0x3f3f3f3f; 24 inline int read(){ 25 char ch=getchar();int x=0,f=1; 26 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 27 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int N,M,T,g[MAXN][MAXN],pack[MAXN*MAXN],f[MAXN][MAXN]; 31 pii light[MAXN*MAXN]; 32 namespace solution{ 33 void init(){ 34 N=read();M=read();T=read(); 35 up(i,1,N){ 36 int x=read(),y=read(); 37 light[i]=make_pair(x,y); 38 } 39 } 40 void pret(){ 41 memset(g,0,sizeof(g)); 42 up(i,1,N){ 43 memset(pack,0,sizeof(pack)); 44 up(j,i,N){ 45 down(k,(N-i+1)*T,light[j].fi)pack[k]=max(max(pack[k],pack[k-1]),pack[k-light[j].fi]+light[j].se); 46 g[i][j]=g[j][i]=pack[(j-i+1)*T]; 47 } 48 } 49 } 50 void DP(){ 51 memset(f,0,sizeof(f)); 52 up(i,1,N)up(k,1,min(M,i))up(j,k,i)f[i][k]=max(f[i][k],f[j-1][k-1]+g[j][i]); 53 cout<<f[N][M]<<endl; 54 } 55 } 56 int main(){ 57 //freopen("input.in","r",stdin); 58 using namespace solution; 59 init(); 60 pret(); 61 DP(); 62 return 0; 63 }
时间: 2024-11-09 21:19:45