HDU
来源:互联网 发布:js offsetwidth取不到 编辑:程序博客网 时间:2024/06/16 22:08
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6107
题目大意:一篇文章,中间有张图片,图片的高度和放的垂直距离可以任意,有若干个长度已知的词,要保持整个词的完整性,词和词不能重叠,词和图不能重叠,词是从最上面开始放,词的顺序不能改变,词和词连续放在一起时要空一行,问放完所有的词和图片所需的最少行数
官方题解:
解题思路:整片文章可以被分成2部分:①中间没有图片的部分;②中间插有图片的部分。所以可以将这2部分分别用ST离线,f[i][j]表示以第i个单词开始,连续2^j行能写多少单词。要注意的是:在第②部分中,如果第一个单词的宽度大于dw和w-pw-dw的话,那么这一段f[i][j]=0
参考来源:http://blog.csdn.net/qq_31759205/article/details/77074650
AC代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 100000 + 5;struct Query{ int xi, hi; Query(int xi = 0, int hi = 0) :xi(xi), hi(hi) {}}Q[MAXN];int St1[MAXN][30], St2[MAXN][30], A[MAXN];int n, w, pw, dw, mx;void toInit(){ mx = 0; memset(St1, 0, sizeof(St1)); memset(St2, 0, sizeof(St2));}void getSt1(){ for (int i = 1;i <= n;++i) { int j = i, ans = 0, flag = 0; while (ans + A[j] + flag <= w&&j <= n) ans += A[j++] + flag, flag = 1; St1[i][0] = j - i; } for (int j = 1;1 << j <= mx;++j)//因为和普通的RMQ不同,所以这里有所区别 for (int i = 1;i <= n;++i) St1[i][j] = St1[i][j - 1] + St1[i + St1[i][j - 1]][j - 1];}void getSt2(){ for (int i = 1;i <= n;++i) { int j = i, ans = 0, flag = 0; while (ans + flag + A[j] <= dw&&j <= n) ans += A[j++] + flag, flag = 1; ans = 0, flag = 0; while (ans + flag + A[j] <= w - dw - pw&&j <= n) ans += A[j++] + flag, flag = 1; St2[i][0] = j - i; } for (int j = 1;1 << j <= mx;++j) for (int i = 1;i <= n;++i) { if (St2[i][j - 1] == 0) St2[i][j] = 0;//以i开始的2^j-1不能放,那么以i开始的2^j行也一定不能放 else St2[i][j] = St2[i][j - 1] + St2[i + St2[i][j - 1]][j - 1]; }}int toRmq1(int i, int x, int St[][30])//占据x行所需要的单词数{ int ans = i; while (x) { int j = 0; while (1 << (j + 1) <= x) j++; x -= 1 << j; ans += St[i][j]; i += St[i][j]; } return ans;}int toRmq2(int i)//以i开始放单词,需要多少行{ int ans = 0; while (i <= n) { int j = 0; while (i + St1[i][j + 1] <= n) j++; ans += 1 << j; i += St1[i][j]; } return ans;}int main(){ int t;scanf("%d", &t); while (t--) { toInit(); scanf("%d%d%d%d", &n, &w, &pw, &dw); for (int i = 1;i <= n;++i) scanf("%d", A + i); int q;scanf("%d", &q); for (int i = 1;i <= q;++i) { scanf("%d%d", &Q[i].xi, &Q[i].hi); mx = max(mx, Q[i].xi + Q[i].hi + n); } getSt1();getSt2(); for (int i = 1;i <= q;++i) { int line = toRmq2(1); if (line <= Q[i].xi - 1)//判断一下x-1行内是不是足够放下所有单词 { printf("%d\n", line + Q[i].hi); continue; } int p = toRmq1(1, Q[i].xi - 1, St1); p = toRmq1(p, Q[i].hi, St2); printf("%d\n", Q[i].xi - 1 + Q[i].hi + toRmq2(p)); } } return 0;}
阅读全文
0 0