HDU 6107 Typesetting(倍增法 17多校第六场)

  • 题目大意

    在一个页面上有n个单词组成的一段话和一个图片,页面宽度、图片宽度、图片两边边距是确定的。告诉了你这段话中每个单词的长度,这些单词在页面中要满足:

    1. 图片上不能放单词
    2. 一行中的连续区间中的两个单词之间要有一个空格

    现在给出Q组询问,每次询问给出一个x和h,x表示图片的起始行数,h表示图片长度
    问这些单词加图片一共覆盖了多少行

  • 分析

    采用倍增的做法
    整个页面可以分为两个部分,有图片的行和没有图片的行
    f1[i][j] 表示不含图片的部分以第i个单词作为开头,行数为 2j 的一段内单词的总数
    f2[i][j] 表示含图片的部分以第i个单词作为开头,行数为 2j 的一段内单词的总数
    然后就是通过倍增的思想对三段分别进行处理

  • 总结
    这道题代码比较难写,边界条件处理起来比较复杂

  • 代码

#include
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<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<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<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<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<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

*/

你可能感兴趣的:(17多校赛)