[2018.09.05 T1] Lyk Love painting

暂无连接

Lyk Love painting

【题目描述】

lyk有一块神奇的画布,呈2*n的格子状。lyk现在想在画布上画m幅画,每幅画必须是矩形。为了充分利用画布,画布上的每一个格子都必须属于某一幅画。

每一个格子都有一个魅力值,一幅画的魅力值为其所包含的格子的魅力值的总和。为了不过于展现自己的才华lyk希望这m幅画魅力值的最大值最小。然而他并不知道如何作画才能达到要求,请你帮帮他吧。

【输入】

第一行两个数n,m

第2、第3行每行n个数,表示每个格子的魅力值

【输出】

仅包含一个整数,为最优方案中最大的魅力值最小可能为多少。

【输入样例】

3 3
1 3 2
1 3 2

【输出样例】

4

【提示】
【数据范围】

对于30%的数据,n ≤ 150, m ≤ 30

对于60%的数据,n ≤ 500, m ≤ 50

对于80%的数据,n ≤ 2000, m ≤ 100

对于100%的数据,n ≤ 100000, m ≤ 100

题解

表示只会 30 30 分暴力,我太菜了

虽然说最大值最小一下就能想到二分,但是当时死活想不出来怎么 check c h e c k ,然后 GG G G 。。。

实际上,我们可以考虑对于一个二分值 mx m x ,询问是否存在一种划分使得整个矩形分为不多于 m m 块且最大值不超过mx

自然想到暴力中的用 dp[i][j] d p [ i ] [ j ] 来表示当划分到第一行第 i i 列,第二行第j列时最少需要分为多少块,但是注意到 n105 n ≤ 10 5 ,只能开下一维来表示当前划分,于是我们只好用 dp[i] d p [ i ] 来表示前 i i 列最少需要划分为多少块。

有一个小小的贪心,每次我们划分出的矩形要尽量大,但是权值和又不能超过mx。所以,我们预处理出 len[1][i] l e n [ 1 ] [ i ] 表示以第一行第 i i 列的方块为结尾宽度为1且权值和不大于 mx m x 的矩形最小的起点列数,同理 len[2][i] l e n [ 2 ] [ i ] 表示第二行第 i i 列的方块为结尾宽度为1且权值和不大于 mx m x 的矩形最小的起点列数, len[3][i] l e n [ 3 ] [ i ] 则表示以第 i i 列结尾宽度为2且权值和不大于 mx m x 的矩形最小的起点列数。

处理出上面的数组后,就有了最简单的一个转移: dp[i]=min(dp[len[3][i]1]+1,dp[i]) d p [ i ] = m i n ( d p [ l e n [ 3 ] [ i ] − 1 ] + 1 , d p [ i ] ) ,当然这个转移只讨论了宽为 2 2 的情况,在两个宽为2的矩形中间还可以填充各式各样的宽度为 1 1 的矩形,我们依旧采用贪心策略,每次都填左端点列数较大的矩形来进行转移。

这样,由于每个点最多跳m次,所以总复杂度为 O(nmlog2(val)) O ( n m l o g 2 ( ∑ v a l ) )

代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int val[3][M],dp[M],len[4][M],n,m,i,j,pre,f1,f2,cot,maxn,sum;
bool check(int mx)
{
    memset(dp,127,sizeof(dp));dp[0]=0;
    for(j=1;j<=2;++j)for(i=pre=1,sum=0;i<=n;++i){sum+=val[j][i];for(;sum>mx;sum-=val[j][pre++]);len[j][i]=pre;}
    for(sum=0,pre=i=1;i<=n;++i){sum+=val[1][i]+val[2][i];for(;sum>mx;sum-=val[1][pre]+val[2][pre++]);len[3][i]=pre;}
    for(i=1;i<=n;++i)
    {
        for(f1=f2=i,cot=0;f1>0&&f2>0&&cot<=m;)
        {
            if(len[1][f1]>len[2][f2])f1=len[1][f1]-1,++cot;
            else if(len[1][f1]<len[2][f2])f2=len[2][f2]-1,++cot;
            else f1=f2=len[1][f1]-1,cot+=2;
            dp[i]=min(dp[i],dp[max(f1,f2)]+cot);
        }
        dp[i]=min(dp[len[3][i]-1]+1,dp[i]);
    }
    return dp[n]<=m;
}
void in(){scanf("%d%d",&n,&m);for(int i=1;i<=2;++i)for(int j=1;j<=n;++j)scanf("%d",&val[i][j]),maxn=max(maxn,val[i][j]);}
void ac(){int le=maxn-1,ri=1e9,mid;while(le^ri){mid=le+ri>>1;check(mid)?ri=mid:le=mid+1;}printf("%d",le);}
int main(){in();ac();}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值