Codeforces 548B Mike and Fun
Mike and some bears are playing a game just for fun. Mike is the judge. All bears except Mike are standing in an n × m grid, there's exactly one bear in each cell. We denote the bear standing in column number j of row number i by (i, j). Mike's hands are on his ears (since he's the judge) and each bear standing in the grid has hands either on his mouth or his eyes.
They play for q rounds. In each round, Mike chooses a bear (i, j) and tells him to change his state i. e. if his hands are on his mouth, then he'll put his hands on his eyes or he'll put his hands on his mouth otherwise. After that, Mike wants to know the score of the bears.
Score of the bears is the maximum over all rows of number of consecutive bears with hands on their eyes in that row.
Since bears are lazy, Mike asked you for help. For each round, tell him the score of these bears after changing the state of a bear selected in that round.
The first line of input contains three integers n, m and q (1 ≤ n, m ≤ 500 and 1 ≤ q ≤ 5000).
The next n lines contain the grid description. There are m integers separated by spaces in each line. Each of these numbers is either 0 (for mouth) or 1 (for eyes).
The next q lines contain the information about the rounds. Each of them contains two integers i and j(1 ≤ i ≤ n and 1 ≤ j ≤ m), the row number and the column number of the bear changing his state.
After each round, print the current score of the bears.
5 4 5
0 1 1 0
1 0 0 1
0 1 1 0
1 0 0 1
0 0 0 0
1 1
1 4
1 1
4 2
4 3
3
4
3
3
4
——————————————————————————————————————————————————————————————
本来挺简单的一道题,我却写得很复杂。不善于分析复杂度是硬伤啊!
———————————————————————————————————————————————————————————————
1. 读入复杂度N×M,这说明若果算法在与N×M相当的复杂度内是可以AC的
2. 对于一个长为L的01序列,可在O(L)时间内得到连续1的最大数目 (the maximum number of consecutive "1" s in it)。
int a[MAX_N]; int ans=0, cur=0; for(int i=1; i<=n; i++){ if(a[i]==1){ cur++; ans=max(ans, cur); } else cur=0; }
这个基本方法我却没想到,把简单问题搞得过于复杂,没怎么仔细考虑就决定用线段树维护,而且这线段树写得还很“丑陋”。
#include<bits/stdc++.h> using namespace std; const int MAX_N=505; //SegT_1 struct node{ int lb, rb; int ma; }T[MAX_N][MAX_N<<2]; void renew(int i, int id){ node &now=T[i][id]; if(now.ma){ now.lb=now.rb=now.ma=0; } else{ now.ma=now.lb=now.rb=1; } } void _renew(int i, int id, int L, int R){ node &fa=T[i][id], &ls=T[i][id<<1], &rs=T[i][id<<1|1]; fa.lb=ls.lb==(R-L+2)>>1?ls.lb+rs.lb:ls.lb; fa.rb=rs.rb==(R-L+1)>>1?rs.rb+ls.rb:rs.rb; fa.ma=max(max(ls.ma, rs.ma), ls.rb+rs.lb); } void insert(int i, int id, int L, int R, int pos){ if(L==R){renew(i, id);return;} int mid=(L+R)>>1; if(pos<=mid) insert(i, id<<1, L, mid, pos); else insert(i, id<<1|1, mid+1, R, pos); _renew(i, id, L, R); } //SegT_2 int mx[MAX_N<<2]; void _insert(int id, int L, int R, int pos, int val){ if(L==R){mx[id]=val; return;} int mid=(L+R)>>1; if(pos<=mid) _insert(id<<1, L, mid, pos, val); else _insert(id<<1|1, mid+1, R, pos, val); mx[id]=max(mx[id<<1], mx[id<<1|1]); } // int main(){ freopen("in", "r", stdin); int N, M, Q; cin>>N>>M>>Q; int a; for(int i=1; i<=N; i++){ for(int j=1; j<=M; j++) if(cin>>a, a) insert(i, 1, 1, M, j); _insert(1, 1, N, i, T[i][1].ma); } int i, j; while(Q--){ cin>>i>>j; insert(i, 1, 1, M, j); _insert(1, 1, N, i, T[i][1].ma); cout<<mx[1]<<endl; } return 0; }
甚至于我还在想能不能在不牺牲时间复杂度的情况下将树状数组改造成支持单点改的RMQ(不想写两个线段树~<^>~),但我真是SB了。这题暴力的复杂度O(q(n+m)) (读入复杂度O(nm)相比之下可忽略了), 1e6的量级,1s完全可过了(况且都说Codeforces的机器快~)。
-----------------------------------------------------------------------------------------------------------------------
写复杂的原因呢,就是我不熟悉求一个01串内最长连续“1”的长度朴素的解法应该怎么写(怎么可以连这都不知道呢~),最终踏上了线段树的歧途。
(×&^伤#¥%), 最要紧的还是要把一些基础姿势get到。