標籤:fine scan can lag check http stdout name out
觀察資料範圍,n*m比較小,所以我們預先處理出首碼和。
然後我們可以考慮寫一個函數來計算二維首碼和(二維首碼和大家都會的吧qwq,那我就不說了,就是要注意一下哪個是橫軸哪個是縱軸)
之後就是二維上的二分位置,然後check看看符不符合二分出來的ans。
- 註:一半求最大化最小值和最小化最大值的問題,都可以往二分想。我們可以把最佳化問題二分後來check轉化為判定問題。
#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#define ll long long#define maxn 550using namespace std;int n,m,lx,rx,ly,ry,aa,bb;ll sum[maxn][maxn]; bool calc(int lx,int down,int rx,int up,int num) {return (sum[rx][up]-sum[rx][down-1]-sum[lx-1][up]+sum[lx-1][down-1])>=num;} bool check2(int num){ bool yes=1;ly=ry=1; for(int j=1;j<=bb;j++) { while(ry+1<=m&&!calc(lx,ly,rx,ry,num)) ry++; if(!calc(lx,ly,rx,ry,num)) {yes=0;break;} ly=++ry; } return yes;}bool check(int num){ bool flag=1; lx=1,rx=1; for(int i=1;i<=aa;i++) { while(rx+1<=n&&!check2(num)) rx++; if(!check2(num)) {flag=0;break;} lx=++rx; } if(flag==1) return true; else return false;} int main(){ freopen("champion.in","r",stdin); freopen("champion.out","w",stdout); scanf("%d%d%d%d",&n,&m,&aa,&bb); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int cur; scanf("%d",&cur); sum[i][j]=sum[i][j-1]+cur; } for(int j=1;j<=m;j++) sum[i][j]+=sum[i-1][j]; } //首碼和 long long l=0,r=sum[n][m],mid; //二分可以取到的答案qwq while(l<r) { mid=(l+r)>>1; if(check(mid)) l=mid+1; else r=mid; } printf("%lld\n",l-1); return 0;}
切蛋糕(二分)(二維首碼和)