【BZOJ】P1766 photo

区间dp

理解了思路贼清晰。
先将点的x,y坐标离线。

状态定义

\(dp_{i,j,k}\)表示覆盖所有的点其x,y坐标满足\(x \in [i,j]\)\(y \ge k\)所需的最小矩形数。

状态转移

两种方法:
1.\(dp_{i,j,k}\)\(dp_{i,x,k}\)\(dp_{x+1,j,k}\)转移过来(\(x\in[i,j-1]\))。区间dp的标准转移形式,不谈。
2.尽可能的放一个最大的矩形。
方法:找到在\([i,j]\)中的最左端的点使得\(y\ge k\)以及最右端的点\(y\ge k\)的两点的x坐标,拿A除以两个的x坐标之差,这个值就是所放矩形的最大高度H。若\(H<k\)说明这个矩形覆盖不到当前所考虑的点,直接跳过,否则就进一步缩小范围,找\(y\)坐标大于\(H\)的左右两端点(设它们的x坐标为\(lx,rx\)),同时查询一波所有\(y\)坐标大于\(H\)的点中的\(y\)坐标的最小值\(h\),那么就有:

\[dp_{i,j,k}=min\{dp_{i,j,k},dp_{lx,rx,h}+1\} \]

代码:

#include<bits/stdc++.h>
using namespace std;
int n,A,B[10010],C[10010],m,sizeB,sizeD,dp[110][110][110],Max[10010],D[10010];
struct node {
    int x,y;
} P[10010];
bool cmp(node XX,node YY) {
    if(XX.x==YY.x)return XX.y<YY.y;
    else return XX.x<YY.x;
}
int main() {
    memset(dp,127,sizeof(dp));
    scanf("%d %d",&n,&A);
    for(int i=1; i<=n; i++)scanf("%d %d",&P[i].x,&P[i].y);
    for(int i=1; i<=n; i++)B[i]=P[i].y,D[i]=P[i].x;
    sort(B+1,B+1+n);
    sort(D+1,D+1+n);
    sizeB=unique(B+1,B+1+n)-B-1;
    sizeD=unique(D+1,D+1+n)-D-1;
    for(int i=1;i<=n;i++){
        int pos=lower_bound(D+1,D+1+sizeD,P[i].x)-D;
        Max[pos]=max(Max[pos],P[i].y);
    }
    for(int i=sizeD; i>=1; i--) {
        for(int j=i; j<=sizeD; j++) {
            for(int k=sizeB; k>=1; k--) {
                if(i==j){
                    if(Max[i]>=B[k])dp[i][j][k]=1;
                    else dp[i][j][k]=0;
                    continue;
                }
                for(int o=i; o<=j-1; o++)dp[i][j][k]=min(dp[i][j][k],dp[i][o][k]+dp[o+1][j][k]);
                int l,r;
                for(l=i;l<=j;l++)if(Max[l]>=B[k])break;
                for(r=j;r>=i;r--)if(Max[r]>=B[k])break;
                if(l>r){
                    dp[i][j][k]=0;
                    continue;
                }
                else if(l==r){
                    dp[i][j][k]=1;
                    continue;
                }
                int y=A/(D[r]-D[l]),res=2e9+7;
                if(y<B[k])continue;
                for(l=i;l<=j;l++)if(Max[l]>y)break;
                for(r=j;r>=i;r--)if(Max[r]>y)break;
                for(int o=l;o<=r;o++)if(Max[o]>y)res=min(res,Max[o]);
                if(res==2e9+7){
                    dp[i][j][k]=min(dp[i][j][k],1);
                    continue;
                }
                int num=lower_bound(B+1,B+1+sizeB,res)-B;
                dp[i][j][k]=min(dp[i][j][k],dp[l][r][num]+1);
            }
        }
    }
    cout<<dp[1][sizeD][1];
    return 0;
}

posted @ 2019-07-21 13:20  TieT  阅读(183)  评论(0编辑  收藏  举报