/**//* 题意:从上到下为1到N层,每一层三个值Wi,Li,Pi,分别表示已有水量,该层容量,手动放水价格 如果某一层的水超过Li,就会自动将全部水往下泄;也可以手动放水 问要使第N层水泄,至少的代价
一个必要条件: 如果第p层被手动放水,在其下的水都要被放走(自动或手动),即水不可能断流!
可以枚举最高放水点p,然后向下计算代价即可O(n^2) n<=15000 TLE 代价的计算: i 如果层i需要手动放水,必须 ∑W[j]<=L[i] j=p 刚才是打算枚举p,然后每次都计算代价,可不可以不用每次都重新计算呢? 对于最高点为p的,其下层需要放水的集合 S[p]={i | ∑W[j]<=L[i]} 而对于p+1的,以p为最高点时层i如果需要手动放水,则以p+1为最高点时也必然要手动放水 因为∑W[j]减小了 即 S[p]∈S[p+1] , i>=p+1 ★★★
i 设A[i] = ∑W[j]-L[i] ,对A[i]排序,这时的A[i]其实就是p=1时的情况了 j=1 推到p=2,只需看A[i]-W[1]是否<=0 是的话表示需要手动放水 推到p=3,只需看A[i]-W[1]-W[2]
用pos记录目前需要手动放水的 A[pos] 如果在枚举p时,pos前的需要手动放水,则枚举p+1时,pos前的也需要手动放水 所以pos这个指针不用回退的
法一:可以按照A[] sort一下,然后从p=1开始推. Sort完后保证了前面的算过的对于后面的也是有效的 法二:由S[p]∈S[p+1] , i>=p+1 可以用一个最大堆来做,对于最高点p,堆存的是p及之下的需要手动放水的层 i从N往前枚举 维护:i+1->i时,加入i,并将堆里不需要手动放水的去掉,得到最终的代价了 启示:有单调性的,排序后就不用重复计算了!! 跟ZJOI 2010 Base 一样的思想,排序后算,指针不用回退! */ #include<cstdio> #include<cstring> #include<algorithm> #include<queue>
using namespace std;
const int MAXN = 15010; const int INF = 1000000000;
struct Level { int W,L,P; int key; bool operator<(const Level &B)const { return key<B.key; } };
Level levels[MAXN];
bool vi[MAXN]; int id[MAXN];
bool cmp(const int &a,const int b) { return levels[a].key<levels[b].key; }
int main() { //freopen("in","r",stdin);
int N; while(~scanf("%d",&N)) { int totalW = 0,nowCost = 0; //fill(vi+1,vi+1+N,false); for(int i=1;i<=N;i++) { id[i]=i; scanf("%d%d%d",&levels[i].W,&levels[i].L,&levels[i].P); totalW += levels[i].W; levels[i].key = totalW-levels[i].L; //if(levels[i].key<=0)// //{ // vi[i]=true; // nowCost+=levels[i].P; //} }
//sort(id+1,id+1+N,cmp);
//int bestP = 1,bestCost = nowCost; //int subW=0,pos=1; //for(int p=2;p<=N;p++) //{ // subW+=levels[p-1].W; // if(vi[p-1])//如果p之前的被算进nowCost来的话要减去 // nowCost-=levels[p-1].P;
// while(pos<=N&&levels[id[pos]].key-subW<=0) // { // if(!vi[id[pos]]&&id[pos]>=p)//p作为最高顶点时,层i需要手动放水,则加上代价 // { // vi[id[pos]]=true; // nowCost+=levels[id[pos]].P; // } // pos++; // } // if(nowCost<bestCost) // { // bestCost = nowCost; // bestP = p; // } //}
/**//******************************************************/ int bestCost = INF,bestP; priority_queue<Level> PQ; for(int i=N;i;i--) { totalW-=levels[i].W; PQ.push(levels[i]); nowCost+=levels[i].P; while(!PQ.empty()&&PQ.top().key-totalW>0)//>0 不用放水的去掉 { nowCost-=PQ.top().P; PQ.pop(); } if(nowCost<bestCost) { bestCost = nowCost; bestP = i; } } /**//******************************************************/
int addW = 0; for(int i=bestP;i<=N;i++) { addW+=levels[i].W; if(addW<=levels[i].L) printf("%d\n",i); } } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|