zoukankan      html  css  js  c++  java
  • 【题解】Typesetting [Hdu6107]

    【题解】Typesetting [Hdu6107]

    传送门:( ext{Typesetting}) ( ext{[Hdu6107]})

    【题目描述】

    有一篇行数无限宽度 (MaxW) 已知的文章,中间有张图片,图片的高度 (h) 和放置的位置 (x) 可以任意,有若干个长度 (a[i]) 已知的词,要保持整个词的完整性,词和词不能重叠,词和图不能重叠,词必须从第一行开始放,词的顺序不能改变,词和词连续放在一行时中间要空一行,问放完所有的词和图片所需的最少行数。

    【输入】

    首先读入一个整数 (T) 表示一共有 (T) 组数据,对于每组数据,将会包括以下内容:

    第一行四个整数 (n,MaxW,PW,LW) 分别表示单词个数,文章宽度,图片宽度和图片左间距(表示图片与左边界相隔的宽度),图片右间距自行计算。

    第二行 (n) 个整数 (a_i) 表示每个单词的长度。

    第三行一个整数 (Q),表示接下来有 (Q) 个询问,接下来 (Q) 行,每行两个整数 (x,h),表示图片将从第 (x) 行开始一共占 (h) 行的位置。

    【输出】

    对于每个询问,输出此时放完所有单词需要的最少行数。

    【样例】

    样例输入:
    2
    2 7 4 3
    1 3
    3
    1 2
    2 2
    5 2
    3 8 2 3
    1 1 3
    1
    1 1
    
    样例输出:
    2
    3
    3
    1
    
    

    【数据范围】

    (100 \%:)
    (T leqslant 10)
    (1 leqslant n,Q,MaxW leqslant 10^5)
    (1 leqslant a_i,PW leqslant MaxW)
    (0 leqslant LW leqslant MaxW-Pw)


    【分析】

    图片的存在很讨厌,可以把有图片和没有图片的分开处理,步骤如下:

    ((1).) 先算 (x-1) 行(对应着 ([1,x-1]))能放多少单词。

    ((2).) 如果放不完的话,再算在只用一部分合法空间的情况下 (h) 行(对应着 ([x,x+h-1]))能放多少单词。

    ((3).) 如果还是没放完,再算剩下的单词需要多少行。

    上述过程均可用倍增实现,用 (dp_{1}[i][j]) 表示在没有图片的情况下,从第 (i) 个单词开始放,使用 (2^j) 行可以放的单词个数,(dp_{2}[i][j]) 表示在有图片的情况下,只使用左右间距构成的空间(2^j) 行可以放的单词个数,照着上面的思路模拟一下就可以了。

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define Re register int
    using namespace std;
    const int N=1e5+3,logN=17;
    int n,x,y,T,Q,PW,LW,RW,maxW,a[N],dp1[N][20],dp2[N][20];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline void sakura(){//预处理
        for(Re i=1,j,tmp,flag;i<=n;++i){
            //dp1[i][j]: 从第i个单词开始(包括i),使用2^j行可以放的单词个数
            j=i-1,tmp=0,flag=0;//flag表示是否要添空格
            while(j<n&&tmp+flag+a[j+1]<=maxW)++j,tmp+=a[j]+flag,flag=1;//暴力枚举初始化
            dp1[i][0]=j-i+1;
            //dp2[i][j]: 从第i个单词开始(包括i),使用被图片覆盖的2^j行可以放的单词个数
            j=i-1,tmp=0,flag=0;
            while(j<n&&tmp+flag+a[j+1]<=LW)++j,tmp+=a[j]+flag,flag=1;//左间距
            tmp=0,flag=0;
            while(j<n&&tmp+flag+a[j+1]<=RW)++j,tmp+=a[j]+flag,flag=1;//右间距
            dp2[i][0]=j-i+1;
        }
        for(Re j=1;j<=logN;++j)
            for(Re i=1;i<=n;++i){
                if(dp1[i][j-1])dp1[i][j]=dp1[i][j-1]+dp1[i+dp1[i][j-1]][j-1];//要注意判断,如果前半部分放不了的话
                if(dp2[i][j-1])dp2[i][j]=dp2[i][j-1]+dp2[i+dp2[i][j-1]][j-1];//不管后半部分怎么折腾都没用
            }
    }
    inline int find1(Re i,Re limit,Re dp[][20]){//从第i个单词开始(现在需要放的位置),使用limit行,条件为dp1/dp2,求无法放到第?个单词
        Re tmp=0;//tmp: 已经使用的行数
        for(Re j=logN;j>=0;--j)
            if(tmp+(1<<j)<=limit)
                i+=dp[i][j],tmp+=(1<<j);
        return i;
    }
    inline int find2(Re i){//在无图片的情况下,放第i~n个单词个单词需要多少行
        Re ans=0;
        for(Re j=logN;j>=0;--j)//不管j有多大,i+dp[i][j]-1永远都<=n
            if(i+dp1[i][j]-1<n)//为了不造成浪费,要找到不能一次全部放完的最大的j,即满足i+dp1[i][j]-1<n
                ans+=(1<<j),i+=dp1[i][j];
        if(i<=n)ans+=(1<<0),i+=dp1[i][0];//如果i!=n+1,使用一下dp1[i][0]把剩下的全部放完
        return ans;
    }
    int main(){
        // freopen("123.txt","r",stdin);
        in(T);
        while(T--){
            in(n),in(maxW),in(PW),in(LW);
            RW=maxW-PW-LW;//maxW:最大宽度 //PW:图片宽度 //LW:左间距 //RW:右间距
            for(Re i=1;i<=n;++i)in(a[i]);
            memset(dp1,0,sizeof(dp1));
            memset(dp2,0,sizeof(dp2));
            sakura();
            in(Q);
            while(Q--){
                in(x),in(y);
                Re need=find2(1);
                if(need<x){printf("%d
    ",need+y);continue;}//不需要使用覆盖图片的部分就可以全部放完
                Re now=find1(1,x-1,dp1);//先跑前面无限制的x-1行
                now=find1(now,y,dp2);//再跑覆盖图片的y行
                printf("%d
    ",x-1+y+find2(now));//最后看还需要再跑多少无图片的行
            }
        }
    }
    
  • 相关阅读:
    java 运算
    java String
    java的数据类型
    Python: str() 和 repr() 的区别
    Linux命令:which
    Linux命令:locate
    Linux命令:ifconfig
    Linux命令:whereis
    Linux命令:rz 和 sz
    Linux命令:scp
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11732440.html
Copyright © 2011-2022 走看看