题目大意
在一个页面上有n个单词组成的一段话和一个图片,页面宽度、图片宽度、图片两边边距是确定的。告诉了你这段话中每个单词的长度,这些单词在页面中要满足:
- 图片上不能放单词
- 一行中的连续区间中的两个单词之间要有一个空格
现在给出Q组询问,每次询问给出一个x和h,x表示图片的起始行数,h表示图片长度
问这些单词加图片一共覆盖了多少行分析
采用倍增的做法
整个页面可以分为两个部分,有图片的行和没有图片的行
用 f1[i][j] 表示不含图片的部分以第i个单词作为开头,行数为 2j 的一段内单词的总数
用 f2[i][j] 表示含图片的部分以第i个单词作为开头,行数为 2j 的一段内单词的总数
然后就是通过倍增的思想对三段分别进行处理总结
这道题代码比较难写,边界条件处理起来比较复杂代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=200005;
int T;
int n,w,pw,lw;//单词数,页面宽度,图片宽度,页左边距
int a[MAXN];
int Q;//查询次数
int xi,hi;
int mx;
int f1[MAXN][30];//f1[i][j]表示从第i个单词开头,占据2^j行能放置的最大单词数
int f2[MAXN][30];//f1[i][j]表示有图片的情况下从第i个单词开头,占据2^j行能放置的最大单词数
void Init_ST()
{
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2))
a[n+1]=w+1;//在最后添加一个虚拟的单词长度超过页面宽度
for(int i=1;i<=n;i++)//求出f1[i][1]
{
int tw=a[i];//宽度
int j=i+1;
while(tw+a[j]+1<=w){tw+=a[j]+1;j++;}
f1[i][0]=j-i;
}
for(int k=1;(1<<k)<=mx;k++)
{
for(int i=1;i<=n;i++)
{
int t=f1[i][k-1];
f1[i][k]=t+f1[i+t][k-1];
}
}
for(int i=1;i<=n;i++)
{
int j=i;
int tw=0;
if(tw+a[j]<=lw){tw+=a[j];j++;}
while(tw+a[j]+1<=lw) {tw+=a[j]+1;j++;}
tw=0;
int rw=w-pw-lw;
if(tw+a[j]<=rw){tw+=a[j];j++;}
while(tw+a[j]+1<=rw){ tw+=a[j]=1;j++;}
f2[i][0]=j-i;
}
for(int k=1;(1<<k)<=mx;k++)
{
for(int i=1;i<=n;i++)
{
int t=f2[i][k-1];
f2[i][k]=t+f2[i+t][k-1];
}
}
}
int RMQ1(int i,int x)//不含图片,以i开头长度为x的段落之后的单词标号
{
if(x==0)return i;
while(x!=0 && i<=n)
{
int j=0;
while((1<<(j+1))<=x)j++;
i+=f1[i][j];
x-=(1<<j);
}
return i;
}
int RMQ2(int i,int x)//含图片,以i开头长度为x的段落之后的单词标号
{
if(x==0)return i;
while(x!=0 && i<=n)
{
int j=0;
while((1<<(j+1))<=x)j++;
i+=f2[i][j];
x-=(1<<j);
}
return i;
}
int RMQ3(int i)//不含图片,以i开头到末尾的行数
{
int ans=0;
while(i<=n)
{
int j=0;
while(i+f1[i][j+1]<=n)j++;
i+=f1[i][j];
ans+=(1<<j);
}
return ans;
}
int Work(int x,int h)
{
int temp=RMQ3(1);
if(temp<=x-1)return temp+h;
int ans=x+h-1;
int i=0;
i=RMQ1(1,x-1);
i=RMQ2(i,h);
if(i<=n)ans+=RMQ3(i);
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
mx=1000000;//设置一个最大的长度
scanf("%d%d%d%d",&n,&w,&pw,&lw);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
Init_ST();
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
scanf("%d%d",&xi,&hi);
printf("%d\n",Work(xi,hi));
}
}
}
/*
2
2 7 4 3
1 3
3
1 2
2 2
5 2
3 8 2 3
1 1 3
1
1 1
*/