简单的dp。
dp[i][j]:在第i位置,递减的状态为j,所获得的最大利润。
枚举状态,如果加进来的数x比状态的最小的要大,那么直接状态变为x。
如果x比最小的要小,那么状态为j+x。
如果x等于最小的,那么依次加和,直至最小的比x大。
#include <iostream> #include<stdio.h> #include<vector> #include<queue> #include<stack> #include<string.h> #include<algorithm> #include<math.h> using namespace std; int pan(int x) { if(x==2)return 1; if(x==4)return 2; if(x==8)return 3; if(x==16)return 4; } int dp[505][1<<13]; int a[550]; queue<int>que; void chu(int s,int ss,int k,int x) { dp[s][x]=max(dp[s][x],dp[ss][0]+x); if(k==0)return; if(dp[ss][k]==0)return; dp[s][k]=max(dp[s][k],dp[ss][k]); while(!que.empty())que.pop(); int y=x; int add=x; for(int i=0; i<13; i++) { int now=(1<<i); if((k&now)==0)continue; if(now<y)dp[s][x]=max(dp[s][x],dp[ss][k]+x); if(now>y)dp[s][k+x]=max(dp[s][k+x],dp[ss][k]+add); if(now!=y)return; y=y*2; add+=y; } dp[s][y]=max(dp[s][y],dp[ss][k]+add); } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); int sum=0; for(int i=1; i<=n; i++) { scanf("%d",&a[i]); sum+=a[i]; } for(int i=1; i<=n; i++) { for(int j=0; j<=sum; j++)dp[i][j]=0; } for(int i=1; i<=n; i++) { for(int j=0; j<=sum; j++) { chu(i,i-1,j,a[i]); } } int maxx=0; for(int i=0; i<=sum; i++)maxx=max(maxx,dp[n][i]); cout<<maxx<<endl; } return 0; }
时间: 2024-11-12 10:56:39