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
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; }