Problem Description
Yellowstar is writing an article that contains N words and 1 picture, and the i-th word contains 
 

 

Input
The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with four integers N, W, pw, dw : the number of words, page width, picture width and left margin.
The next line contains N integers w
 
Output
For each query, output one integer denotes the minimum number of rows.
 
Sample Input
2 2 7 4 3 1 3 3 1 2 2 2 5 2 3 8 2 3 1 1 3 1 1 1
 
Sample Output
2 3 3 1
 
 
题意:
  给你n个单词,放到宽度是W的文档里,每个单词不能跨行,在一行的连续的单词必须有空格隔开
  现在,在第 xi 行 距离文档左边框 dw的位置 放一个 宽度pw ,长度hi 的 图片,现在把单词全部填上去,问最少占多少行(只要有单词或者图片都算被占)
题解:
  设定f[i][j],表示以 第 i 个单词 开始 给你 2^j行 能放到第几个单词
  pw, dw,w是给定的,所以我们对于所有询问,无非就是  三种 宽度, 我们用倍增预处理三种宽度的 f 数组就行了
  我写的挫,复杂度:O(Q*logn*logn + n*logn)
下面给出AC代码
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 2e5+10, M = 1e3+20,inf = 2e9;

int f[N][25],n,w,pw,dw,a[N],g[N][25];
LL sum[N];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d%d",&n,&w,&pw,&dw);
        for(int i = 1; i <= n; ++i) scanf("%d",&a[i]);
        memset(g,0,sizeof(g));
        memset(f,0,sizeof(f));
        sum[0] = 0;
        for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + 1LL*a[i] + 1LL;
        for(int i = 1; i <= n; ++i)
        {
            int l = i,r = n;
            while(l <= r) {
                int md = (l + r) >> 1;
                if(sum[md] - sum[i-1] - 1<= 1LL*w) f[i][0] = md,l = md+1;
                else r = md-1;
            }

            l = i,r = n;
            int now = -1;
            while(l <= r) {
                int md = (l + r) >> 1;
                if(sum[md] - sum[i-1] - 1 <= 1LL*dw) now = md,l = md+1;
                else r = md-1;
            }

            if(now == -1) g[i][0] = i-1;
            else g[i][0] = now;

            l = g[i][0] + 1,r = n,now = -1;
            while(l <= r) {
                int md = (l + r) >> 1;
                if(sum[md] - sum[g[i][0]] - 1 <= 1LL*(w - pw - dw)) now = md,l = md+1;
                else r = md-1;
            }
            if(now != -1) g[i][0] = now;
        }
        for(int j = 1; j <= 18; ++j)
              for(int i = 1; i <= n; ++i){
                if(f[i][j-1] == n) f[i][j] = n;
                else f[i][j] = f[f[i][j-1] + 1][j-1];
            }
          for(int j = 1; j <= 18; ++j)
              for(int i = 1; i <= n; ++i){
                if(g[i][j-1] == n) g[i][j] = n;
                else
                g[i][j] = g[g[i][j-1] + 1][j-1];
            }

        int Q;
        scanf("%d",&Q);
        while(Q--) {
            int x,h;
            scanf("%d%d",&x,&h);

            x -= 1;

            int now = 0,l,r,ans;
            for(int i = 18; i >= 0; --i)
                if(((x>>i)&1) && now != n)now = f[now+1][i];
            if(now == n) {
                l = 1; r = x,ans = 1;
                while(l <= r) {
                    int md = (l+r)>>1;
                    now = 0;
                    for(int i = 18; i >= 0; --i)
                        if(((md>>i)&1) && now != n)now = f[now+1][i];
                    if(now == n) ans = md,r = md-1;
                    else l = md+1;
                }
                printf("%d\n",ans + h);
                continue;
            }

            int tmp = now;
            for(int i = 20; i >= 0; --i)
                if(((h>>i)&1) && now != n) now = g[now+1][i];
            if(now == n) {
                printf("%d\n",h + x);
                continue;
            }
            tmp = now;
            l = 0; r = 100005,ans = 100005;
            while(l <= r) {
                int md = (l+r)>>1;
                now = tmp;
                for(int i = 18; i >= 0; --i)
                    if(((md>>i)&1) && now != n)now = f[now+1][i];
                if(now == n) ans = md,r = md-1;
                else l = md+1;
            }
            printf("%d\n",x + ans + h);
        }
    }
    return 0;
}

 

相关文章: