暂无连接
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 块且最大值不超过。
自然想到暴力中的用 dp[i][j] d p [ i ] [ j ] 来表示当划分到第一行第 i i 列,第二行第列时最少需要分为多少块,但是注意到 n≤105 n ≤ 10 5 ,只能开下一维来表示当前划分,于是我们只好用 dp[i] d p [ i ] 来表示前 i i 列最少需要划分为多少块。
有一个小小的贪心,每次我们划分出的矩形要尽量大,但是权值和又不能超过。所以,我们预处理出 len[1][i] l e n [ 1 ] [ i ] 表示以第一行第 i i 列的方块为结尾宽度为且权值和不大于 mx m x 的矩形最小的起点列数,同理 len[2][i] l e n [ 2 ] [ i ] 表示第二行第 i i 列的方块为结尾宽度为且权值和不大于 mx m x 的矩形最小的起点列数, len[3][i] l e n [ 3 ] [ i ] 则表示以第 i i 列结尾宽度为且权值和不大于 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 的情况,在两个宽为的矩形中间还可以填充各式各样的宽度为 1 1 的矩形,我们依旧采用贪心策略,每次都填左端点列数较大的矩形来进行转移。
这样,由于每个点最多跳次,所以总复杂度为 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();}