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;}
原创粉丝点击