题目链接:https://vjudge.net/problem/Gym-100451J
解题思路:
明显每一步花费的时间不会超过t+1,那么我们先按照这个规则先放满n个数进去,也就是如果第一个周期的数超过t+1时换到第2个周期。。。,但是这样并不是最优解,因为虽然最大值不会超过t+1,但也不说明它会趋近于t+1,这时我们就要找它真正的趋近值,如果我们现在要在已经放满n个里面再放进下一个周期数为x,那么就要把相同的个数中前x大的数取出来,如果是可以节省花费的,那么就放入,否则结束。那么我们再放入的数肯定不会超过n个。那么关于取最大值就可以用一个set或者优先队列维护了。
再用一个标记数组,最后用于判断巧克力在什么时候吃的。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mx = 1e6 + 10;
int n,m,siz,q[mx],c[mx];
multiset <int> st;
int check(int up)
{
auto it = --st.end();
ll ans = -m;
int time = 1,cnt = 0;
while(1){
if(time<*it) ans += *it - time,cnt++;
else break;
if(it==st.begin()) break;
time += up,it--;
}
if(ans>0) return cnt;
return 0;
}
void solve()
{
int pos = 1,up = 1;
while(c[1]){
int time = 1;
while(c[time]){
c[time]--;
time += up;
pos++;
}
q[siz++] = pos-1,up++;
}
}
int main()
{
scanf("%d%d",&n,&m);
int time = 1,up = 1;
ll ans = 0;
for(int i=1;i<=n;){
if(time>m+1){
time = 1,up++;
ans += m;
}else{
ans += time;
c[time]++;
st.insert(time);
time += up,i++;
}
}
while(1){
auto it = --st.end();
if(*it>time){
ans -= *it - time;
c[time]++,c[*it]--;
st.insert(time);
st.erase(it);
time += up;
}else{
int cnt = check(++up);
if(cnt){
ans += m,time = 1;
while(cnt--){
ans -= *it - time;
c[time]++,c[*it]--;
st.erase(it--);
st.insert(time);
time += up;
}
}
else break;
}
}
printf("%lld\n",ans);
solve();
printf("%d\n",--siz);
for(int i=0;i<siz;i++) printf("%d%c",q[i],i==siz-1?'\n':' ');
return 0;
}