http://codeforces.com/contest/680/problem/E

题目大意:给你一个n*n的图,然后图上的 . (我们下面都叫做‘点’)表示可以走,X表示不能走,你有如下的操作,每次你可以选择一个k*k的框,把其中的所有的X都变成 ‘点’,问在该操作后点相连的数目最多是多少?

没看别人代码和思路自己思考并优化了好久,于是敲了两个多小时。。。还是代码能力太差了

思路:当然最最单纯的做法就是O(n^4)。为了优化,起初想用二维树状数组+并查集的,结果发现窗口中的‘点‘’容易造成重复计算,于是换了种方法,每次事先统计‘点’和X,然后再每次暴力枚举边就好了。复杂度O(n*n*4*4*k*log)

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = + ;
int par[maxn * maxn], cnt[maxn * maxn];
bool vis[maxn * maxn];
int n, k;
char ch[maxn][maxn];
int dx[] = {, , -, };
int dy[] = {, , , -}; int bfs(int x, int y, int fa){
queue<pair<int, int> > que;
que.push(mk(x, y));
int cnt = ;
while (!que.empty()){
pair<int, int> u = que.front(); que.pop();
for (int i = ; i < ; i++){
int nx = u.fi + dx[i], ny = u.se + dy[i];
if (nx <= || ny <= || nx > n || ny > n) continue;
if (ch[nx][ny] != '.' || vis[nx * n + ny]) continue;
vis[nx * n + ny] = true;
cnt++;
par[nx * n + ny] = fa;
que.push(mk(nx, ny));
}
}
return cnt;
} int pointcnt[maxn * maxn];
inline int init(int i){
for (int x = ; x <= n; x++)
for (int y = ; y <= n; y++)
pointcnt[x * n + y] = vis[x * n + y] = ; int cntx = ;
for (int x = i; x <= k + i - ; x++)///take care of border
for (int y = ; y < k; y++){///最后一列先不放进去
if (ch[x][y] == '.') pointcnt[par[x * n + y]]++;
if (ch[x][y] == 'X') cntx++;
}
return cntx;
} int solve(){
int ans = ;
for (int i = ; i <= n - k + ; i++){
int cntx = init(i);
for (int y = ; y <= n - k + ; y++){///四个方向的遍历
///clear上一列的,insert目前列的
for (int x = i; x <= i + k - ; x++){
if (ch[x][y - ] == '.') pointcnt[par[x * n + y - ]]--;
else if (ch[x][y - ] == 'X') cntx--;
if (ch[x][y + k - ] == '.') pointcnt[par[x * n + y + k - ]]++;
else if (ch[x][y + k - ] == 'X') cntx++;
}
int pin = ;
vector<int> v;
///左右列, 变行
for (int x = i; x <= i + k - ; x++){
for (int j = ; j < ; j++){
int nx = x + dx[j], ny = y + dy[j];
if (nx <= || ny <= || nx > n || ny > n) continue;
if (ch[nx][ny] != '.') continue;
int pos = par[nx * n + ny];
if (vis[pos]) continue;
vis[pos] = true; v.push_back(pos); pin += pointcnt[pos];
}
for (int j = ; j < ; j++){
int nx = x + dx[j], ny = y + k - + dy[j];
if (nx <= || ny <= || nx > n || ny > n) continue;
if (ch[nx][ny] != '.') continue;
int pos = par[nx * n + ny];
if (vis[pos]) continue;
vis[pos] = true; v.push_back(pos); pin += pointcnt[pos];
}
}
///上下行,变列
for (int yy = y; yy <= y + k - ; yy++){
for (int j = ; j < ; j++){
int nx = i + dx[j], ny = yy + dy[j];
if (nx <= || ny <= || nx > n || ny > n) continue;
if (ch[nx][ny] != '.') continue;
int pos = par[nx * n + ny];
if (vis[pos]) continue;
vis[pos] = true; v.push_back(pos); pin += pointcnt[pos];
}
for (int j = ; j < ; j++){
int nx = i + k - + dx[j], ny = yy + dy[j];
if (nx <= || ny <= || nx > n || ny > n) continue;
if (ch[nx][ny] != '.') continue;
int pos = par[nx * n + ny];
if (vis[pos]) continue;
vis[pos] = true; v.push_back(pos); pin += pointcnt[pos];
}
}
int len = v.size();
int tmp = k * k - pin;
for (int i = ; i < len; i++){
tmp += cnt[v[i]];
vis[v[i]] = false;
}
ans = max(ans, tmp);
}
}
return ans;
} int main(){
scanf("%d%d", &n, &k);
for (int i = ; i <= n; i++) scanf("%s", ch[i] + );
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
par[i * n + j] = i * n + j;
for (int i = ; i <= n; i++){
for (int j = ; j <= n; j++){
if (ch[i][j] == '.' && !vis[i * n + j]){
vis[i * n + j] = true;
cnt[i * n + j] = bfs(i, j, i * n + j);
}
}
}
printf("%d\n", solve());
return ;
}

然后敲完之后跑出来是2600ms,然后有人是300ms左右就过了的,具体思路差不多,大概就是我初始化+vector多了一堆没用的东西导致复杂度变得很高了。

不过我也看了一下他们的代码发现,果然差距还是好大

代码来源:http://blog.csdn.net/Fsss_7/article/details/51706546#reply

#include<bits/stdc++.h>
using namespace std;
const int N=;
typedef long long ll;
typedef unsigned long long ull;
char s[N];
int n,a[*N][*N],b[N][N];
int g=,q[N*N],f[N*N],xm[N*N],ym[N*N],xx[N*N],yx[N*N]; ///这里应该就是单纯的跑一下,然后知道目前联通块的边界
void dfs(int x,int y) {
b[x][y]=g;f[g]++;///标记是第几个联通快,和记录着联通块的数目
xm[g]=min(xm[g],x);xx[g]=max(xx[g],x);
ym[g]=min(ym[g],y);yx[g]=max(yx[g],y);
if (x>&&b[x-][y]==-) dfs(x-,y);
if (x<n&&b[x+][y]==-) dfs(x+,y);
if (y>&&b[x][y-]==-) dfs(x,y-);
if (y<n&&b[x][y+]==-) dfs(x,y+); } int main(){
int i,j,h,k,tot,ans=;
scanf("%d%d", &n, &k);
for (i=;i<=n;i++) {
scanf("%s", s);
for (j=;j<=n;j++)
if (s[j-]=='.') b[i][j]=-;///存在点
else {
b[i][j]=;///不是点
a[i][j]+=;a[i][j+k]+=-;///然后标记障碍物所对应的方框
a[i+k][j]+=-;a[i+k][j+k]+=;
}
}
memset(xm,0x7f,sizeof(xm));
memset(ym,0x7f,sizeof(ym));
for (i=;i<=n;i++)
for (j=;j<=n;j++)
if (b[i][j]==-) {
g++,dfs(i,j);
if (xx[g]-xm[g]+<=k&&yx[g]-ym[g]+<=k) {///边界超过K的就不会被k*k包围啦,然后对边界进行处理
a[xx[g]][yx[g]]+=f[g]; a[xm[g]+k][ym[g]+k]+=f[g];//左上右下
a[xx[g]][ym[g]+k]-=f[g]; a[xm[g]+k][yx[g]]-=f[g];//左下右上
}
} for (int i = ; i <= n; i++){
for (int j = ; j <= n; j++){
printf("%d ", a[i][j]);
}
cout << endl;
} for (i=;i<=n;i++)///a[i][j]是统计(i,j)~(i-k, j-k)这个矩形中,只在内部的‘点’和X的数目
for (j=;j<=n;j++)
a[i][j]+= a[i][j-] + a[i-][j] - a[i-][j-];
for (i=k;i<=n;i++)
for (j=k;j<=n;j++) {///枚举(k,k)开始的端点
tot=;
for (h=j-k+;h<=j;h++)///左列
if (!q[b[i-k][h]]) q[b[i-k][h]]=,tot+=f[b[i-k][h]];///用q标记该连通块是否被访问过,然后b所记录的是第几个块的标号
for (h=j-k+;h<=j;h++)///右列
if (!q[b[i+][h]]) q[b[i+][h]]=,tot+=f[b[i+][h]];
for (h=i-k+;h<=i;h++)///上行
if (!q[b[h][j-k]]) q[b[h][j-k]]=,tot+=f[b[h][j-k]];
for (h=i-k+;h<=i;h++)///下行
if (!q[b[h][j+]]) q[b[h][j+]]=,tot+=f[b[h][j+]];
ans=max(ans,tot+a[i][j]);
printf("tot = %d a[%d][%d] = %d\n", tot, i, j, a[i][j]);
///printf("a[%d][%d] = %d\n", i, j, a[i][j]);
///初始化
for (h=j-k+;h<=j;h++) q[b[i-k][h]]=;
for (h=j-k+;h<=j;h++) q[b[i+][h]]=;
for (h=i-k+;h<=i;h++) q[b[h][j-k]]=;
for (h=i-k+;h<=i;h++) q[b[h][j+]]=;
}
printf("%d\n", ans);
return ;
}

并查集+bfs+暴力滑窗 Codeforces Round #356 (Div. 2) E的更多相关文章

  1. Codeforces Round #356 (Div. 1) D. Bear and Chase 暴力

    D. Bear and Chase 题目连接: http://codeforces.com/contest/679/problem/D Description Bearland has n citie ...

  2. Codeforces Round #356 (Div. 2)-A

    A. Bear and Five Cards 题目链接:http://codeforces.com/contest/680/problem/A A little bear Limak plays a ...

  3. Codeforces Round #356 (Div. 2)-B

    B. Bear and Finding Criminals 链接:http://codeforces.com/contest/680/problem/B There are n cities in B ...

  4. Codeforces Round #356 (Div. 2) C. Bear and Prime 100(转)

    C. Bear and Prime 100 time limit per test 1 second memory limit per test 256 megabytes input standar ...

  5. Codeforces Round #356 (Div. 2)B. Bear and Finding Criminals(水题)

    B. Bear and Finding Criminals time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  6. Codeforces Round #356 (Div. 2)A. Bear and Five Cards(简单模拟)

    A. Bear and Five Cards time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  7. dfs Codeforces Round #356 (Div. 2) D

    http://codeforces.com/contest/680/problem/D 题目大意:给你一个大小为X的空间(X<=m),在该空间内,我们要尽量的放一个体积为a*a*a的立方体,且每 ...

  8. Codeforces Round #356 (Div. 1) C. Bear and Square Grid

    C. Bear and Square Grid time limit per test 3 seconds memory limit per test 256 megabytes input stan ...

  9. Codeforces Round #356 (Div. 2) E. Bear and Square Grid 滑块

    E. Bear and Square Grid 题目连接: http://www.codeforces.com/contest/680/problem/E Description You have a ...

随机推荐

  1. [!] Error installing AFNetworking

    cocoaPods 报错!!! [!] Error installing AFNetworking[!] /usr/local/bin/git clone https://github.com/AFN ...

  2. Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件(二)

    Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件第二版 上次粗略的写了相同功能的代码,这次整理修复了之前的一些BUG,结构也大量修改 ...

  3. The most orzed and orzing man

    The most orzed and orzing man 题目链接:http://acm.xidian.edu.cn/problem.php?id=1184 Sprague-Grundy定理:htt ...

  4. kali Rolling安装之后的一些常用配置总结

    添加普通用户 useradd -m -G sudo,video,audio,cdrom -s /bin/bash OKing把某个用户添加到组中: sudo usermod -a 用户名 -G 组名 ...

  5. GitHub版本控制工具入门(一)

    你还在使用 SVN 吗? 那就太 low 了... 概述 要了解 github 要从另外一个软件开始,那就是 git ,他的中文意思是 傻子 ,这款软件为什么要起一个这么傻的名字呢? 那你就需要了解一 ...

  6. 彻底解决tap“点透”,提升移动端点击响应速度

    申明!!!最后发现判断有误,各位读读就好,正在研究中.....尼玛水太深了 前言 近期使用tap事件为老夫带来了这样那样的问题,其中一个问题是解决了点透还需要将原来一个个click变为tap,这样的话 ...

  7. 分享给大家一个简单的数据导出excel类

    <?php /** * 生成excel文件操作 * * @author wesley wu * @date 2013.12.9 */ class Excel { private $limit = ...

  8. mysql表设计

    model表 记录网站模块:如视频,音频,调查,01发布内容时.可以指定发布到哪个模块下02可以统计每个模块的访问量设计表注意点01主键不要用id (全部使用 当前表名+id 如modelid)02n ...

  9. Python之生产者&、消费者模型

    多线程中的生产者和消费者模型: 生产者和消费者可以用多线程实现,它们通过Queue队列进行通信. import time,random import Queue,threading q = Queue ...

  10. jquery选择器的简单使用

    1.$()可以是$(expresion),即css选择器.Xpath或html元素,也就是通过上述表达式来匹配目标元素. 比如:$("a")构造的这个对象,是用CSS选择器构建了一 ...