[好好学习] kick start round c- B

鉴于Round E要到了...  错过这个村就没这个店了0.0所以整理一下
此处加一个大纲。markdown在博客园怎么用…… 
算了格式在这先发出来吧。。and  要有目标qwq。!

## 题目2 Circuit Board

这个在LeetCode上的84 是个经典问题。LeetCode我都还只做到了.. 反正很少的,也没有接手Hard,easy感觉总是水水过去,medium也很少很少。
下一步说不定可以在github上维护一下?分单独的题解和分开的题解……完全可以在幕布上写了再移植过去的。(心情复杂.jpg)也可以不移植

### 题意

300*300矩阵,给定一大堆数字,使得每行中的最大值、最小值的差不超过K,满足这些条件的最小子矩阵是多少。

### false (大部分false的删了……)

o(n^3)的做法。
开始想的是并查集归属,串串儿一样噜过去,但是其实有点emmmm
对于这样的情况,只连续的找到个体然后从个体开始蔓延是不行的。
2 2 2 4 
4 2 2 2 
2 2 2 4
有种感觉,你需要抛开种族偏见,不能这样狭隘的去想,而且n很小,可以直接枚举两维,再来一维
首先呢,我们用一个三维布尔数组来记录,f[i][l][r],记录的是i行的从 l 处到 r 处,此段里能否达到"不超过E"的条件。
这里是很死板的,甚至不用考虑最大值如果有两个的问题,只需预处理,枚举l和r。
好。如果布尔类型已经确定了

### 布尔怎么更新?

想了想,还是要至少更新n*(n-1)/2个。
那真的好笑。如果跟前面比是可,然后大小都没越界,
当前我在的位置是a2,当前已有len匹配到了(算了a2) ,那么1~ a2-len填No,a2-len+1 ~ a2填Yes(true)。
大小越界怎么看呢?
嗯,这个好像也是有时效性的,用最笨 的办法,那不如 满足K的时候正着来,不满足的时候1~a2-len+1依然可,后面一边走一边维护tmpmax和tmpmin
再想。
如果直接维护l和r呢?
嗯,这里,思维的差距就体现出来了。我们我在上面写的方法可以是可以,但是相当麻烦,而且有没有感觉到,有一种"特殊化"的感觉。
抛开这些再想想,在本文末尾,有提供一维怎么解答,可以nlogn,但没必要。
这个处理是和主程序分开写的,完全可以分开写,枚举的意思就是...
直接暴力的l和r,哪怕n^2的直接跑一遍,每次只看一个名为“l到r"的区间,只写一个false or true。即使这样n平方复杂度也足够了
剥离出来统一的看,思维要上升一个高度。。

### true =================================

我觉得好蠢哦,上面可以验证都是false的,高度根本不用管。
与其这样写题解,还是自己捋顺了是最好的吧……
……………………
这个题只有一句话。枚举l和r,那么这个串串的宽度是确定的,l和r已经n^2了
宽度确定后,到底有多长,就直接判断yes和no,然后使用累加,再乘以r-l+1就可了。
为什么要这么做?题中说要验证最长的块,那么是长度(横着)确定,去竖着撸一下更好呢,还是竖着确定,横着撸一串最好呢
显然,应该长度确定,然后看有几行能符合这个条件。直接一行一行看就可以了(图一)
如果是宽度确定的话,即使是继续扩展,是没用的,因为并不是以这个作区分的,可以看到1 1 3 这样按照这种划分方式并不能说明,因为这也不是题目的本意。 (图二)
那么写一下代码。好累啊打解析打的手疼我不想写了(buxing
写个例子:
99 3 4 0 
2 2 2 3          
3 2 2 2 
2 2 2 3
26分到手……  思路理清之后,是没问题的,只是我写错了一个== , 一个就是更新的时候没把1,1这样的首部更新进去
关键是思路啊!!!这还是很简单的啊!!!!26分啊!!!!kickstart错过就没了啊啊啊啊!!!
 
最后粘一下代码
#include
#include
#include
using namespace std;
int n;
bool f[305][305][305];
int a[305][305];
int a1, a2, k;
int main() {
 int t; cin >> t;
 int kase = 0;
 while (t--) {
  //f好像不用清空 直接初始化就好
  //输入 
  cin >> a1 >> a2 >> k;
  for (int i = 1; i <= a1; i++) {
   for (int j = 1; j <= a2; j++) {
    cin >> a[i][j];
   }
  }
 
  //对数据处理 初始化bool f
  bool ff; int now;
  
  for (int i = 1; i <= a1; i++) {//
   for (int left= 1; left <= a2; left++) { //下面的列
    f[i][left][left] = true;
    int maxx = a[i][left]; int minn = a[i][left];
    //【惊!我这里多写了个等号】
    //【惊!2 我忘记把第一个考虑进去!了耶】
    ff = true;
    for (int right = left+1 ; right <= a2; right++) {
     if (ff == false)f[i][left][right] = false;
     else {
      now = a[i][right];
      maxx = max(maxx, now);
      minn = min(minn, now);
      if (minn + know)
       ff = false;
      f[i][left][right] = ff;
     }
     //这个数和minn maxx比较一下就好了 同时更新一下
     // 如果已经是false了 那就全盘都是false好l
    }
   }
  }
 /*
  for (int i = 1; i <= a1; i++) {//行
   for (int left = 1; left <= a2; left++) { //下面的列
    for (int right = left; right <= a2; right++) {
     cout << f[i][left][right]<<" ";
    }
    cout << endl;
   }
   cout << endl;
  }
 
  */
  int maxans = -1;int ans = 0;
  // ... 好.. 那处理完了还剩一次最后的循环和拍
  for (int l = 1; l <= a2; l++) {
   for (int r = l; r <= a2; r++) {
    ans = 0;
    for (int i = 1; i <= a1; i++) {
     if (f[i][l][r] == true) {
      ans += (r - l + 1);
      maxans = max(ans, maxans);
     }
     else {
      ans = 0;
     }
    }
   }
  }
  cout <<"Case #"<<++kase<<": "<< maxans << endl;
 }
 return 0;
}
 

 

### 变形

但就是说这样题目是个有名的变形,还有:
这个是... 饿示意图..  这个题目的意思相当于是让我们这样求。实际上可以转化到leetcode的这样题目:
 
 
 

### 问题扩展:

#### 如果是一维的?

看起来直接横着过去就行。可以则加,不行则扔
但是有个问题,就是最大值最小值,如果是 3 4 5 7 2 7 后面来了个1,这不是完了吗,简单的双指针失效了。
有点作弊的做法:用mutiset。
而且要s.erase(s.find(7)) 这样只会删除一个,否则两个7都没了
看最大的只要s.rbegin()即可。越界就往前走(删除),不越界就安全,可以达到nlogn复杂度。

#### 如果是三维的?

想象一下,实际上n^5来 n^4在限制长度,相当于一个长方形桶,满足则继续,好像预处理有点麻烦

转载于:https://www.cnblogs.com/lx2331/p/11370111.html

你可能感兴趣的:([好好学习] kick start round c- B)