SGU 148 解题手记(+解题报告)
最朴素的,用c[k,v]表示淹掉第k层,且能够给第k+1层灌进v重量的水要花的钱:c[k,v]=min{ P(k)|(if W(k)>=v) , c[k-1,max{v,L(k)+1}-W(k)] }。最后所求是c[N,0]。但这样做空间尚且可以解决,无奈时间复杂度太大了。
但暂时想不到好办法,拿这个试一试吧。
不行,没办法记录决策。
发现有人写过《SGU 148 解题报告》,而且讲的已经非常清楚了。我对它有所修改,因为原文的Wi被定义了两次。
Submit 1: WA on 2。n=1的时候没处理。
Submit 2: WA on 5。编码上有点问题,B被pop成空集之后没有处理。
Submit 3: WA on 5。出这种错误真是太无语了,建堆的时候居然用Si作为key……应该用Ci。
Submit 4: AC。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <queue> #include <cstdio> #include <algorithm> using namespace std; struct lev { int id,C,S,P; }; bool operator <(const lev& a,const lev& b) { return a.C<b.C; } int main() { lev levels[15001]; levels[0].S=0; priority_queue<lev> B,minB; int n,cost(0),mincost(225000001); scanf("%d",&n); for (int i=1;i<=n;i++) { levels[i].id=i; int w,l; scanf("%d%d%d",&w,&l,&levels[i].P); levels[i].S=levels[i-1].S+w; levels[i].C=levels[i].S-l; } for (int i=n;i>=1;i--) { while (B.size() && B.top().C>levels[i-1].S) { cost-=B.top().P; B.pop(); } B.push(levels[i]); cost+=levels[i].P; if (cost<mincost) { mincost=cost; minB=B; } } while (!minB.empty()) { printf("%d\n",minB.top().id); minB.pop(); } return 0; } |
5 Responses
sgu148oibh上的这种解法我不太理解,
如何用快速排序生成那个次序?
可否解释下
“贪心的主要思路是枚举第一个花钱减压的水层,每次计算总的花费,这样算是o(n^2)的算法,难以接受。所以我们要做一些优化。
如果是从最后一层开开始枚举,我们会发现当枚举第i层时,凡是第i层下面的水层,只有可能由需要花钱减压变为不需要花钱减压,当枚举到第1层时这个变化最多有n次。所以只需找到发生这种变化的水层的次序就可以在o(n)的时间内完成贪心。这个次序可以用快速排序来生成,所以总的时间复杂度为o (nlogn)。”
Reply
请问出了你的blog以外,还有哪些比较好的sgu解题报告,最好是pascal的
Reply
最著名的SGU解题报告是IOI中国国家队SGU表格。
其次还有Amber(http://adn.cn/blog)的SGU题解。但现在已经不公开提供了。
还有Only the Strong Survive。
还有DD的SGU之旅。
还有NOT A BLOG | sqybi。
Reply
thanks
Reply
国家队的表格哪里有?
Reply
Top Seven
Recent Comments
Categories
Blogroll
Login
Sponsor