HDU 6107 Typesetting(ST)

15 篇文章 0 订阅

Description

N 个单词一个图片,第i个单词有 ai 个字符,页面宽度可以容纳 W 个字符,为了好看有以下约束:

1.图片宽度是pw,图片左边距页面左边距离为 dw ,右边距页面距离 Wpwdw

2.单词和图片均不能重叠

3.单词的先后顺序不能改

4.一个单词不能跨行,要在同一行

5.如果两个单词在同一行的连续位置,那么要用空格隔开

6.最小化单词和图片所占行数

给出 Q 次查询,每次给出图片的开始行x和高度 h ,问这n个单词和这张图片至少要占多少行

Input

第一行一个整数 T 表示用例组数,每组用例首先输入四个整数N,W,pw,dw分别表示单词数,一行可容纳字符数,图片宽度以及图片距页面左边界距离,之后输入 N 个整数ai表示第 i 个单词的字符数量,之后输入一整数Q表示查询数,最后 Q 行每行输入两整数x,h表示图片的开始行和图片的高度

(T10,1N,W,Q105,1pw,aiW,0dwWpw)

Output

对于每次查询,输出这 n 个单词和这张图片至少占的行数

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

Solution

f1[i][j]表示以第 i 个单词开始占用没有图片的2j行最多可以放的单词数量, f2[i][j] 表示以第 i 个单词开始占用有图片的2j行最多可以放的单词数,用ST求出这两个数组后,对于每次查询,首先求出全部单词会占用多少没有图片的行数 ans ,如果 ans 不超过 x1 行说明单词不会到放置图片的行,答案即为 ans+h ,如果 ans 大于 x1 则求出前 x1 行最多可以放置的单词数 y ,然后从第y+1个单词开始看用有图片的 h 行可以放多少单词,如果已经够放下这n个单词则答案为 x+h1 ,否则还有多拿一些行来放剩下的单词

Code

#include<cstdio>
#include<algorithm>
using namespace std;
namespace fastIO 
{
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror=0;
    inline char nc() 
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if(p1==pend) 
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if(pend==p1) 
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) 
    {
        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x) 
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
    }
    inline void readc(char &x)
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        x=ch;
    }
    inline void reads(char *x)
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        int n=0;
        while(1)
        {
            x[n++]=ch;
            if(blank(ch=nc()))break;
        }
        x[n]='\0';
    }
    #undef BUF_SIZE
};
using namespace fastIO;
#define maxn 100005
int f1[maxn][20],f2[maxn][20];
int T,n,w,pw,dw,a[maxn],q,b[maxn][2],m;
void ST()
{
    for(int i=1;i<=n;i++)
    {
        int sum=a[i],j=i+1;
        while(j<=n&&sum+a[j]+1<=w)sum+=a[j]+1,j++;
        f1[i][0]=j-i;
    }
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i<=n;i++)
            f1[i][j]=f1[i][j-1]+f1[i+f1[i][j-1]][j-1];
    for(int i=1;i<=n;i++)
    {
        int sum=0,space=0,j=i;
        while(j<=n&&sum+a[j]+space<=dw)sum+=a[j]+space,j++,space=1;
        sum=0,space=0;
        while(j<=n&&sum+a[j]+space<=w-pw-dw)sum+=a[j]+space,j++,space=1;
        f2[i][0]=j-i;
    }
    for(int j=1;(1<<j)<=m;j++)
        for(int i=1;i<=n;i++)
            f2[i][j]=f2[i][j-1]+f2[i+f2[i][j-1]][j-1];
}
int RMQ1(int s)
{
    int ans=0;
    while(s<=n)
    {
        int j=0;
        while((1<<(j+1))<=n&&s+f1[s][j+1]<=n)j++;
        s+=f1[s][j];
        ans+=(1<<j);
    }
    return ans;
}
int RMQ2(int s,int h)
{
    if(h==0)return s;
    while(h&&s<=n)
    {
        int j=0;
        while((1<<(j+1))<=h)j++;
        s+=f1[s][j];
        h-=(1<<j);
    }
    return s;
}
int RMQ3(int s,int h)
{
    if(h==0)return s;
    while(h&&s<=n)
    {
        int j=0;
        while((1<<(j+1))<=h)j++;
        s+=f2[s][j];
        h-=(1<<j);
    }
    return s;
}
int main()
{
    read(T);
    //scanf("%d",&T);
    while(T--)
    {
        read(n),read(w),read(pw),read(dw);
        //scanf("%d%d%d%d",&n,&w,&pw,&dw);
        for(int i=1;i<=n;i++)read(a[i]);//scanf("%d",&a[i]);
        read(q);
        //scanf("%d",&q);
        m=0;
        for(int i=1;i<=q;i++)
        {
            read(b[i][0]),read(b[i][1]);
            //scanf("%d%d",&b[i][0],&b[i][1]);
            m=max(m,b[i][1]);
        }
        ST();
        for(int i=1;i<=q;i++)
        {
            int x=b[i][0],h=b[i][1];
            int ans=RMQ1(1);
            if(ans<=x-1)printf("%d\n",ans+h);
            else
            {
                ans=x+h-1;
                int y=RMQ2(1,x-1);
                y=RMQ3(y,h);
                if(y<=n)ans+=RMQ1(y);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值