算法训练-Don't fear, DravDe is kind
#include<bits/stdc++.h> using namespace std; int n,dp[100001],v[100001],c[100001],l[100001],r[100001],maxx=0,ok[100001],ll,num=0,m=0; vector<int> hash[100000]; //方法:使用一维数组,dp[a]表示有a且以a为结尾的最大值,那么a的前后数目都确定了, //对于1<=k<a,判断l[k]+c[k]和l[a],来决定可不可以有k,同样r[k]!=c[a]+r[a]; //初始值:对于l[a]==0的都可以作为第一个,则return v[a] //可以改用循环更快 int DP(int a){ if(l[a]==0) return v[a]; if(dp[a]!=0) return dp[a]; for(vector<int>::iterator i=hash[l[a]].begin();i!=hash[l[a]].end();i++){ if(*i>=a||r[*i]!=c[a]+r[a]) continue;//因为用了hash,可能*i>=a,本来会循环到a-1的,不会出现这种情况 if(DP(*i)+v[a]>dp[a]){ dp[a]=DP(*i)+v[a]; ok[a]=*i;//前驱数组 } } if(dp[a]>maxx&&r[a]==0){//r[a]==0才更新最优解,平常不限制最后一个r[a]==0,否则无法循环。都是0; maxx=dp[a]; ll=a;//最优值的位置 } return dp[a]; } void show(int k){ if(k==-1) return; m+=v[k]; show(ok[k]); cout<<k<<" "; } int main() { cin>>n; memset(dp,0,sizeof(dp)); memset(ok,255,sizeof(ok)); for(int i=1;i<=n;i++){ cin>>v[i]>>c[i]>>l[i]>>r[i]; hash[c[i]+l[i]].push_back(i); } for(int i=1;i<=n;i++) DP(i); //保证得到最优解,其实只需循环r[i]==0的点就行了, //但是事实上,后面的都会用到前面的,因为我是递归,所以直接递归后面反而会变慢 int p=ll; while(ll!=-1){ ll=ok[ll]; num++; } cout<<num<<endl; show(p); cout<<endl; cout<<maxx<<endl; return 0; }