Atcoder 题面传送门 & 洛谷题面传送门

首先 \(n^5\) 的暴力非常容易想,设 \(dp_{a,b,c,d}\) 表示以 \((a,b)\) 为左上角,\((c,d)\) 为右下角的矩阵的 complexity。枚举断点转移即可,时间复杂度 \(n^5\)。

我们考虑优化这个 \(dp\),首先比较明显的一点:这个 \(dp\) 状态满足单调性,也就是说 \(\forall d_1<d_2,dp_{a,b,c,d_1}\le dp_{a,b,c,d_2}\),也就是说对于某个 \(dp\) 状态 \(dp_{a,b,c,d}\),假设最大的满足 \(dp_{a,b,c,k}<dp_{a,b,k+1,d}\) 的 \(k\) 为 \(r\),那么我们从行处切开的决策点 \(k\) 要么为 \(r\),要么为 \(r+1\),这个异常好想,于是我们可以二分这个 \(r\) 然后从 \(r\) 和 \(r+1\) 转移即可,时间复杂度 \(n^4\log n\),用双针也可优化到 \(n^4\)。

不过仅仅进行这个优化是远远不够的,我们还需进一步优化。这一步就有亿点考验观察力了,不难发现这个答案不会太大,手玩几组数据可看出这个答案最大不过 \(\log n\) 级别(当然如果硬要说理的话用二维线段树的思想也可以解释),也就是说我们 \(dp\) 数组的值域最大大概在 \(16\) 左右。所以我们可以很自然地想到一个类似于函数里面“交换定义域和值域”的思路:将答案放入 \(dp\) 状态中。

我们重新设计 \(dp\) 状态。设 \(f_{x,l,r,c}\) 表示最大的 \(y\) 满足 \(dp_{x,y,l,r}\leq c\)。转移分两种情况,横着切或者竖着切。如果我们横着切,那么我们肯定会贪心地选择最大的 \(dp_{x,y,l,r}\leq c-1\) 的 \(y\) 作为分割点,也就是说 \(f_{x,l,r,c}\leftarrow f_{f_{x,l,r,c-1}+1,l,r,c}\)。如果我们竖着切,考虑枚举断点 \(k\) 并从 \(k\) 与 \(k+1\) 之间切开,那么 \(dp_{x,y,l,r}\leq c\) 就意味着 \(dp_{x,y,l,k}\leq c-1,dp_{x,y,k+1,r}\leq c-1\),故我们用 \(\min(f_{x,l,k,c-1},f_{x,k+1,r,c-1})\) 更新 \(f_{x,l,r,c}\)。这样暴力更新还是 \(n^4\log n\) 的。不过还是按照之前的套路,由 \(dp\) 数组满足单调性也可推出 \(f\) 数组也满足单调性,即 \(\forall r_1<r_2,f_{x,l,r_1,c}\ge f_{x,l,r_2,c}\),于是我们二分断点转移即可,复杂度就降到了 \(n^3\log^2n\)。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define fi first
  4. #define se second
  5. #define fill0(a) memset(a,0,sizeof(a))
  6. #define fill1(a) memset(a,-1,sizeof(a))
  7. #define fillbig(a) memset(a,63,sizeof(a))
  8. #define pb push_back
  9. #define ppb pop_back
  10. #define mp make_pair
  11. template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
  12. template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
  13. typedef pair<int,int> pii;
  14. typedef long long ll;
  15. typedef unsigned int u32;
  16. typedef unsigned long long u64;
  17. namespace fastio{
  18. #define FILE_SIZE 1<<23
  19. char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
  20. inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
  21. inline void putc(char x){(*p3++=x);}
  22. template<typename T> void read(T &x){
  23. x=0;char c=getchar();T neg=0;
  24. while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
  25. while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
  26. if(neg) x=(~x)+1;
  27. }
  28. template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
  29. template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
  30. void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
  31. }
  32. const int MAXN=185;
  33. const int MAXANS=17;
  34. int n,m,sum[MAXN+5][MAXN+5];char s[MAXN+5][MAXN+5];
  35. int f[MAXN+5][MAXN+5][MAXN+5][MAXANS+1];
  36. int main(){
  37. scanf("%d%d",&n,&m);
  38. for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
  39. for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
  40. sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(s[i][j]=='.');
  41. }
  42. for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=j;k<=m;k++){
  43. int l=i,r=n,p=i-1;
  44. while(l<=r){
  45. int mid=l+r>>1,ss=sum[mid][k]-sum[mid][j-1]-sum[i-1][k]+sum[i-1][j-1];
  46. if(ss==0||ss==(mid-i+1)*(k-j+1)) p=mid,l=mid+1;
  47. else r=mid-1;
  48. } f[i][j][k][0]=p;
  49. }
  50. for(int p=1;p<=MAXANS;p++) for(int i=1;i<=n;i++) for(int len=1;len<=m;len++)
  51. for(int j1=1,j2=len;j2<=m;j1++,j2++){
  52. f[i][j1][j2][p]=f[i][j1][j2][p-1];
  53. chkmax(f[i][j1][j2][p],f[f[i][j1][j2][p-1]+1][j1][j2][p-1]);
  54. if(f[i][j1][j2][p]==n) continue;
  55. int l=j1,r=j2-1;
  56. while(l<=r){
  57. int mid=l+r>>1;
  58. chkmax(f[i][j1][j2][p],min(f[i][j1][mid][p-1],f[i][mid+1][j2][p-1]));
  59. if(f[i][j1][mid][p-1]<f[i][mid+1][j2][p-1]) r=mid-1;
  60. else l=mid+1;
  61. }
  62. }
  63. int ans=-1;
  64. for(int i=0;i<=MAXANS;i++) if(f[1][1][m][i]<n) chkmax(ans,i);
  65. printf("%d\n",ans+1);
  66. return 0;
  67. }

Atcoder Grand Contest 033 D - Complexity(dp)的更多相关文章

  1. AtCoder Grand Contest 031 B - Reversi(DP)

    B - Reversi 题目链接:https://atcoder.jp/contests/agc031/tasks/agc031_b 题意: 给出n个数,然后现在你可以对一段区间修改成相同的值,前提是 ...

  2. Atcoder Grand Contest 021 F - Trinity(dp+NTT)

    Atcoder 题面传送门 & 洛谷题面传送门 首先我们考虑设 \(dp_{i,j}\) 表示对于一个 \(i\times j\) 的网格,其每行都至少有一个黑格的合法的三元组 \((A,B, ...

  3. Atcoder Regular Contest 089 D - ColoringBalls(DP)

    Atcoder 题面传送门 & 洛谷题面传送门 神仙题. 在下文中,方便起见,用 R/B 表示颜色序列中球的颜色,用 r/b 表示染色序列中将连续的区间染成的颜色. 首先碰到这一类计算有多少个 ...

  4. AtCoder Grand Contest 032-B - Balanced Neighbors (构造)

    Time Limit: 2 sec / Memory Limit: 1024 MB Score : 700700 points Problem Statement You are given an i ...

  5. AtCoder Grand Contest 012 B - Splatter Painting(dp)

    Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement Squid loves painting v ...

  6. Atcoder Grand Contest 001E - BBQ Hard(组合意义转化,思维题)

    Atcoder 题面传送门 & 洛谷题面传送门 Yet another 思维题-- 注意到此题 \(n\) 数据范围很大,但是 \(a_i,b_i\) 数据范围很小,这能给我们什么启发呢? 观 ...

  7. AtCoder Grand Contest 033

    为什么ABC那么多?建议Atcoder多出些ARC/AGC,好不容易才轮到AGC…… A 签到.就是以黑点为源点做多元最短路,由于边长是1直接bfs就好了,求最长路径. #include<bit ...

  8. Atcoder Grand Contest 038 E - Gachapon(Min-Max 容斥+背包)

    Atcoder 题面传送门 & 洛谷题面传送门 我竟然能独立做出 Ag 的 AGC E,incredible!更新了 Atcoder 做题难度上限( 首先按照套路 Min-Max 容斥,\(a ...

  9. AtCoder Grand Contest 033 题解

    传送门 我比赛的时候怕不是在睡觉啊-- \(A\ Darker\ and\ Darker\) 我是不是想得太复杂了--根本没必要像我这样做吧-- 首先问题可以转化成令\(p_{i,j}\)表示到\(( ...

随机推荐

  1. Zookeeper+Dubbo环境搭建与Demo测试

     环境准备: 1. zookeeper-3.4.14     (下载地址:http://archive.apache.org/dist/zookeeper/) 2. dubbo-0.2.0 (下载地址 ...

  2. 【UE4 调试】C++ 常见编译 warnnings/errors

    error LNK2019: unresolved external symbol "" referenced in function 描述 Link错误.无法解析的外部符号 解决 ...

  3. 注解,@Qualifier+@Autowired 和 @Resource

    摘要: 项目中,对于AOP的使用,就是通过用注解来注入的. 更改之前的注解,是使用:@Qualifier+@Autowired   但是,通过这样注解,在项目启动阶段,需要自动扫描的过程是非常缓慢的, ...

  4. 防止SQL注入总结

    1.预编译(占位符)可以很大程度上防止SQL注入 预编译的原理是数据库厂商提供的JAR包中,对参数进行了转义 2.mybatis中,能用# 的地方,不用$,因为#是预编译占位符形式,可以防止SQL注入 ...

  5. [CPP] 类的内存布局

    本文可以解决下面 3 个问题: 以不同方式继承之后,类的成员变量是如何分布的? 虚函数表及虚函数表指针,在可执行文件中的位置? 单一继承.多继承.虚拟继承之后,类的虚函数表的内容是如何变化的? 在这里 ...

  6. 「笔记」$Min\_25$筛

    总之我也不知道这个奇怪的名字是怎么来的. \(Min\_25\)筛用来计算一类积性函数前缀和. 如果一个积性函数\(F(x)\)在质数单点是一个可以快速计算的关于此质数的多项式. 那么可以用\(Min ...

  7. Linux C语言链表你学会了吗?

    链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...

  8. 你知道怎么从jar包里获取一个文件的内容吗

    目录 背景 报错的代码 原先的写法 编写测试类 找原因 最终代码 背景 项目里需要获取一个excle文件,然后对其里的内容进行修改,这个文件在jar包里,怎么尝试都读取不成功,但是觉得肯定可以做到,因 ...

  9. Java 16 新功能介绍

    点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 程序猿阿朗博客 已经收录,有很多知识点和系列文章. Ja ...

  10. 策略路由——使用Router-Policy策略路由进行路由协议的引入

    1.实验目的:实现R3-R2-R1为访问主线路,R3-R4-R1为访问备份线路 2.实验拓扑及IP,如图; 3.基本配置(端口IP) R1: <Huawei>sys[Huawei]sys ...