CF254E Dormitory 题解
RedLycoris · · 题解
题目大意:
有
你还有
你每天可以选择一些朋友供应食物(必须供给正好
同时,你每天必须吃
问你
题解:
令
转移:
很显然,我们每一天肯定会先吃昨天的剩饭,不够了再吃今天的饭。
然后选择朋友的话,我们可以贪心的选:按照朋友的饭量从小到大排序,选最小的前
具体可以参考代码
Code:
const int mxn=444;
int n,v,m;
int a[mxn];
vector<pair<int,int> >c[mxn];
int dp[mxn][mxn*2],pre[mxn][mxn*2],preg[mxn][mxn*2]; //pre[][]记录剩饭由哪儿转移过来,preg记录了当天请了饭量前多少小的朋友吃饭
inline void solve(){
cin>>n>>v;
for(int i=1;i<=n;++i)cin>>a[i];
cin>>m;
for(int i=1;i<=m;++i){
int l,r,t;cin>>l>>r>>t;
for(int j=l;j<=r;++j)c[j].push_back(mp(t,i));
}
for(int i=1;i<=n;++i)sort(c[i].begin(),c[i].end());
for(int i=0;i<mxn;++i)for(int j=0;j<mxn*2;++j)dp[i][j]=-1145141;
dp[1][0]=0;
for(int i=1;i<=n;++i){
for(int j=0;j<=800;++j){//dp[i][j]表示考虑到第i天,昨天剩下了j的食物所能得到的最大值
if(dp[i][j]<0)continue;
int yes=j,tod=a[i]; //分别代表昨天的剩饭和今天新增的饭
if(yes>=v)yes-=v;
else tod-=(v-yes),yes=0; //先处理今天自己吃的饭
int x=tod+yes;
if(dp[i][j]>dp[i+1][tod]){
dp[i+1][tod]=dp[i][j];
pre[i+1][tod]=j;
preg[i+1][tod]=0;
}
int sum=0;
for(int k=0;k<c[i].size();++k){
sum+=c[i][k].first;
if(sum>x)break;
int rem=min(tod,x-sum); //还是先吃剩饭,然后处理昨天不能保留到明天的饭
if(dp[i][j]+k+1>dp[i+1][rem]){
dp[i+1][rem]=dp[i][j]+k+1;
pre[i+1][rem]=j;
preg[i+1][rem]=k+1;
}
}
}
}
int pos=0;
for(int i=1;i<=800;++i)if(dp[n+1][i]>dp[n+1][pos])pos=i;
cout<<dp[n+1][pos]<<'\n';
vector<int>bk;
bk.clear();
int lst=pos;
for(int i=n+1;i>1;--i){
bk.push_back(preg[i][lst]);
lst=pre[i][lst];
}
for(int i=bk.size()-1;~i;--i){
cout<<bk[i]<<' ';
for(int j=0;j<bk[i];++j)cout<<c[bk.size()-i][j].second<<' ';
cout<<'\n';
}
}
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T=1;
//cin>>T;
for(;T--;)solve();
return 0;
}