↑懒懒的我终于换成折叠态代码,然而不知道怎么把这个框框弄掉。。)
H second large rectangle
0725upd:参考于https://www.cnblogs.com/DeaphetS/p/11229389.html
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxn = 1000 + 5; int l[maxn][maxn], r[maxn][maxn], h[maxn][maxn]; bool mp[maxn][maxn]; int n, m, ml, mr; int ma, sma, mlx, mly,mrx,mry, slx, sly,srx,sry, curm,curs, curx, cury; int main() { cin >> n>>m; char a; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { cin >> a; mp[i][j]=a-'0'; if (mp[i][j]) { l[i][j] = r[i][j] = j; h[i][j] = 1;//悬线法初始化处理 } } for (int i = 1; i <= n; i++) { for (int j = 2; j <= m; j++) if (mp[i][j] && mp[i][j - 1])l[i][j] = l[i][j - 1];//左推 for (int j = m - 1; j >= 1; j--) if (mp[i][j] && mp[i][j + 1])r[i][j] = r[i][j + 1];//右推 for (int j = 1; j <= m; j++) { if (i != 1 && mp[i][j] && mp[i - 1][j]) { h[i][j] = h[i - 1][j] + 1; l[i][j] = max(l[i][j], l[i - 1][j]); r[i][j] = min(r[i][j], r[i - 1][j]);//画框框 } int cur = (r[i][j] - l[i][j] + 1) * h[i][j];//当前面积 int lx, ly, rx, ry; lx = i - h[i][j] + 1; rx = i; ly = l[i][j]; ry = r[i][j];//左上角与右下角坐标 · //↓判断是否是同一个矩形! if (cur >= curm && (lx != mlx || ly != mly || rx != mrx || ry != mry)) { curs = curm, curm = cur; slx = mlx, mlx = lx; sly = mly, mly = ly; srx = mrx, mrx = rx; sry = mry, mry = ry; }//更新最大面积与次大面积 if(cur>curs&&cur<curm){ slx = lx, sly = ly; srx = rx, sry = ry; curs = cur; }//更新次大面积 curx = (rx - lx) * (ry - ly + 1), cury = (ry - ly) * (rx - lx + 1); if (curx > curs) curs = curx, slx = lx + 1, sly = ly, srx = rx, sry = ry; if (cury > curs) curs = cury, slx = lx, sly = ly + 1, srx = rx, sry = ry; //宽和长分别减一行看看是不是次大 } } cout << curs << endl; return 0; }
赛中 Thor:你之前不是做过类似的题吗?看看这题
红小豆内心:啊我终于能写题了! 实践后:n4、n3这时间复杂度不行啊。。。
赛后学习预备知识:悬线法o(n2)记录当前点所在悬线的左边界和右边界以及向上可达的高(该条悬线的高)
赛后补题写了个朴素的悬线法(作用都是一样的呀(#`O′))然后只过60%的数据。在面向题解编程的过程中,发现不是悬线法处理的问题,是同一个矩形的判断的问题(就是那两个条件奇奇怪怪的if)。因为不想写结构体的 . 于是开了一堆变量。。
还有用单调栈做的大佬,emmm,单调栈,了解一下。
本来想整场比赛补完再一起更新的,结果补到B题开始学习数学基础,暂且告辞_(:з」∠)_
0730upd:
E MAZE
参考于:https://www.cnblogs.com/DeaphetS/p/11222740.html
又是快乐的线段树,加上了快乐的转移矩阵,甚至还有快乐的输入方式,三倍的快乐
从前有一个东西叫做转移矩阵,在红小豆目前看来就像是建图的时候的邻接矩阵。
比如说,对于迷宫 0 0 0 1 0 第一行的转移矩阵长这样 1 1 1 0 0
1 0 0 1 0 1 1 1 0 0
第二行的长这样 0 0 0 0 0 1 1 1 0 0
0 1 1 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0 0 1
0 0 0 0 0
0 0 0 0 1 从第一行到第二行就进行矩阵乘运算
得到了这个东西 0 0 0 0 0 获得了方案数呢,sugoi!
2 2 2 0 0
2 2 2 0 0
0 0 0 0 0
0 0 0 0 1 线代飘过的人需要好好学线代了_(:з」∠)_
那么,对于每次询问,我们需要做的就是将第一行开始到第n行的转移矩阵乘起来,(1,a)到(n,b)的方案数就是矩阵(a,b)的结果
所以要进行的操作有获取单位矩阵、获取迷宫改变后的对应行的矩阵并更新、进行矩阵乘法、查询某几行的转移矩阵和输入(认真脸
区间查询区间修改使用了线段树,脑补出好大一棵满是矩阵的线段树感到莫名有趣wwwww
输入迷宫的时候尝试了两种方法,需要吞回车的getchar不太适合这里呢,两种方法运行了一下,getchar那份慢了200ms
写线段树的时候试图偷懒,结果搞不清左子右子和左边界右边界的区别了,从头再来orz
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long LL; int n, m, q; bool mp[50005][15]; char s[50005]; const LL mod = 1e9 + 7; struct mx { LL tn[15][15]; void init() { for (int i = 1; i <= m; i++) for (int j = 1; j <= m; j++) tn[i][j] = 0; } mx operator* (const mx& t)const { mx res; res.init(); for (int i = 1; i <= m; i++) for (int j = 1; j <= m; j++) for (int k = 1; k <= m; k++) res.tn[i][j] = (res.tn[i][j] + tn[i][k] * t.tn[k][j] % mod) % mod; return res; } void e() { for (int i = 1; i <= m; i++) for (int j = 1; j <= m; j++) tn[i][j] = (i == j); } void get(int i) { init(); int l = 1, r = 1; for (int j = 1; j <= m; j++) { if (mp[i][j]) { l = r = j + 1; continue; } while (r <= m && mp[i][l] == mp[i][r])r++; r--; for (int k = l; k <= r; k++)tn[k][j]++; } } }; struct st { #define ls i<<1 #define rs i<<1|1 struct node { mx v; int l, r; }po[50005 << 2]; void puu(int i) { po[i].v = po[ls].v * po[rs].v; } void build(int l, int r, int i) { po[i].l = l, po[i].r = r; if (l == r) { po[i].v.get(l); return; } int mid = (l + r) >> 1; build(l, mid, ls); build(mid + 1, r, rs); puu(i); } void cha(int i, int c) { int l = po[i].l, r = po[i].r; if (l == c && r == c) { po[i].v.get(c); return; } int mid = (l + r) >> 1; if (mid >= c)cha(ls, c); else cha(rs, c); puu(i); } mx qy(int l, int r, int i) { if (po[i].l >= l && r >= po[i].r)return po[i].v; mx res; res.e(); int mid = (po[i].l + po[i].r) >> 1; if (mid >= l)res = res * qy(l, r, ls); if (mid < r)res = res * qy(l, r, rs); return res; } }seg; int main() { scanf("%d%d%d", &n, &m, &q); /*for (int i = 1; i <= n; i++){ scanf("%s", s+1); for (int j = 1; j <= m; j++) mp[i][j] = s[j] - '0'; }*/ getchar();//吞回车 for (int i = 1; i <= n; i++, getchar())//吞回车+1 for (int j = 1; j <= m; j++) mp[i][j] = getchar() - '0'; seg.build(1, n, 1); for (int i = 0; i < q; i++) { int p, a, b; scanf("%d%d%d", &p, &a, &b); if (p == 1) { mp[a][b] ^= 1; seg.cha(1, a); } else { mx t = seg.qy(1, n, 1); printf("%lld\n", t.tn[a][b]); } } return 0; }
今天依然是起名不超过三个字符的我(๑•̀ㅂ•́)و✧(永远的build除外)