『题解』CodeForces CF548B Mike and Fun
题目大意
有一个 \(n \times m\) 的 \(01\) 矩阵 \(a\)。要进行 \(q\) 次操作,每次操作将 \(a_{x,y}\) 取反,并询问连续的 \(1\) 最多的一行中连续的 \(1\) 的个数。
\(1 \le n,m \le 500,1 \le q \le 5000,1 \le x \le n,1 \le y \le m\)。
思路
可以先考虑暴力。
完全按照题目中说的做,遍历每一行,在每行中找到连续的 \(1\) 最多的个数,总时间复杂度 \(\mathcal{O}(nmq)\)。
然而...TLE on #15。
不知道那几篇暴力题解咋过的,可能是数据又加强了吧。
然后就要考虑更快的办法了。
很容易发现,每次操作影响的只是一行,只需花 \(\mathcal{O}(m)\) 的时间将这一行重新统计一遍就行了。
可以在输入时先算出每行最多的连续个数,存入数组。在询问时 \(\mathcal{O}(n)\) 的时间遍历一遍数组求出最大值。
那么总时间复杂度就是 \(\mathcal{O}(nm+(n+m)q)\)。
嘿嘿,这下你卡不到我了吧...
代码
暴力(TLE)
#include <iostream>
using namespace std;
const int N=5e2+5;
int n,m,q,x,y,sum,ans;
bool a[N][N];
int main(){
cin >> n >> m >> q;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
cin >> a[i][j];
}
}
while(q--){
cin >> x >> y;
a[x][y]=!a[x][y]; // 取反
for(int i=1; i<=n; i++,sum=0){ // 别忘了把 sum 置 0
for(int j=1; j<=m; j++){
if(a[i][j]) sum++; // 还是连续的,则加一
else sum=0; // 碰到一个 0,连续就断了
ans=max(ans,sum); // 每次都更新一下答案
}
}
cout << ans << endl;
ans=0; // 初始化
}
return 0;
}
预处理
#include <iostream>
using namespace std;
const int N=5e2+5;
int n,m,q,x,y,sum,ans;
bool a[N][N];
int mp[N];
int main(){
cin >> n >> m >> q;
for(int i=1; i<=n; i++,sum=0){ // 别忘了把 sum 置 0
for(int j=1; j<=m; j++){
cin >> a[i][j];
if(a[i][j]) sum++; // 还是连续的,则加一
else sum=0; // 碰到一个 0,连续就断了
mp[i]=max(mp[i],sum); // 每次都更新一下答案
}
}
while(q--){
cin >> x >> y;
a[x][y]=!a[x][y]; // 取反
mp[x]=0; // 这句不能忘
for(int i=1; i<=m; i++){
if(a[x][i]) sum++;
else sum=0;
mp[x]=max(mp[x],sum);
}
for(int i=1; i<=n; i++){
ans=max(ans,mp[i]); // 找最大值
}
cout << ans << endl;
sum=0,ans=0; // 初始化
}
return 0;
}