[2018.09.05 T1] Lyk Love painting

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/82430968

暂无连接

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 分暴力,我太菜了

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

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

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

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

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

这样,由于每个点最多跳 m 次,所以总复杂度为 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();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/82430968
lyk
t1