zoukankan      html  css  js  c++  java
  • AGC033D Complexity

    题意

    给出一个(n*m)(0,1)矩阵,若一个矩阵中的所有元素都相同,则这个矩阵的代价为(0),如果不是则选择一种将它分成两个子矩阵的方案,代价为所有方案中(两个子矩阵的代价的较大值+(1))的最小值。
    (n,m leq 185)
    传送门

    思路

    (dp[ i ][ j ][ k ][ l ]) 表示左上角是 $( i , j ) $ 、右下角是 $ ( k , l ) $的矩阵的最小代价,四维扛不住。

    因为如果每次从中间分,(log(n)+log(m))次就变成(1*1)的格子,代价是 (0),所以答案最多是(log(n)+log(m))

    因此可以将值放进状态中,$dp[ i ][ j1 ][ j2 ][ k ] $表示左上角是 (( i , j1 ))、右上角是 $ ( i , j2 ) $ 、用$ k $的代价,往下最长能延伸到哪行。

    转移的时候考虑横着切与竖着切。令$ d = dp[ i ][ j1 ][ j2 ][ k ]$ :

    • 横着切:$ d = dp space [ dp[ i ][ j1 ][ j2 ][ k-1 ] +1] space [ j1 ][ j2 ][ k-1 ] $;

    • 竖着切([ j1 , j3 ] 和 [ j3+1 , j2 ]) 就是分出的两部分;
      (dp[ i ][ j1 ][ j3 ][ k-1 ])(dp[ i ][ j3+1 ][ j2 ][ k-1 ])的最小值是答案,(d)为最小值中的最大值。至此我们得出了(O(m))的暴力转移。
      因为(dp)值明显随矩阵增大而减小,所以可二分(j3)。考虑二分找出最大的(min( dp[ i ][ j1 ][ j3 ][ k-1 ] , dp[ i ][ j3+1 ][ j2 ][ k-1 ] ))。(左比右大往左,反过来,总之越接近越好)

    初始化出所有(k=0)的情况即可

    #include <bits/stdc++.h>
    const int N=190;
    using std::max;
    using std::min;
    int n,m,a[N][N],sum[N][N],dp[N][N][N][15];
    char c[N][N];
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) scanf("%s",c[i]+1);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			if (c[i][j]=='.') a[i][j]=1;
    			else a[i][j]=0;
    			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
    		}
    	for (int i=1;i<=n;i++)	
    		for (int j=1;j<=m;j++)
    			for (int k=j;k<=m;k++){
    				int l=i,r=n,ans=i-1;
    				while (l<=r){
    					int mid=(l+r)>>1;
    					int s=sum[mid][k]-sum[mid][j-1]-sum[i-1][k]+sum[i-1][j-1];
    					if (s==0 || s==(mid-i+1)*(k-j+1))
    						ans=mid,l=mid+1;
    					else r=mid-1;
    				}
    				dp[i][j][k][0]=ans;
    			}
    	int k=1;
    	for (k=1;dp[1][1][m][k-1]<n;k++)
    	for (int h=1;h<=m;h++)
    		for (int i=1;i<=n;i++)
    			for (int j1=1,j2=j1+h-1;j2<=m;j1++,j2++){
    					if (dp[i][j1][j2][k-1]==n){
    						dp[i][j1][j2][k]=n;
    						continue;
    					}
    					dp[i][j1][j2][k]=dp[dp[i][j1][j2][k-1]+1][j1][j2][k-1];//横
    					if(dp[i][j1][j2][k]==n) continue; 
    					int l=j1,r=j2-1,ans=0;//竖 
    					while (l<=r){
    						int mid=(l+r)>>1;
    						int x=dp[i][j1][mid][k-1],y=dp[i][mid+1][j2][k-1];
    						ans=max(ans,min(x,y));
    						if (x<y) r=mid-1;
    						else l=mid+1;
    					}
    	
    					dp[i][j1][j2][k]=max(dp[i][j1][j2][k],ans);
    				}
    	printf("%d
    ",k-1);
    }
    
    * 生而自由 爱而无畏 *
  • 相关阅读:
    B
    R
    C
    B
    异步解决方案----Promise与Await
    NPM 与 Nodejs
    借助node.js + mysql 学习基础ajax~
    bind、call、apply的区别与实现原理
    私有 npm 仓库的搭建
    学习 Promise,掌握未来世界 JS 异步编程基础
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11719366.html
Copyright © 2011-2022 走看看