Codeforces Round #501 (Div. 3)

最近很是浮躁啊。。div3做出来两题。。rating1234->1230...

究其原因还是因为自己菜吧

不谈了,补个题

B. Obtaining the String

不多说,少了一个break

D. Walking Between Houses

也不想说,爆int

E1. Stars Drawing (Easy Edition)

E2. Stars Drawing (Hard Edition)

直接两题一起放上来吧,题意都是一样的,数据范围不一样。

大概就是给你一个图,让你在里面找星星,看能否覆盖所有的星号,能就输出各个星星的中心点和半径,不能就-1

Easy Edition : 3 <= n, m <= 100

Hard Edition : 3 <= n, m <= 1000

简单版本没啥好说的,n^3暴力就能过,说一下优化

预处理出来每个点的相邻的上下左右的星星个数

再遍历每个点,取一个上下左右的最小值(合法),然后把这个点记录下来

再check一下由记录下来的星星组成的图是否与给出的重合,不行-1,可以就输出答案

时间复杂度O(n *m * C),C是常数,不会超过10

空间复杂度不谈~

这题数据感觉略水,我用的重新建图再判断是否重合的方法感觉在极限数据(n==m==1000 除了四角都是*)的情况下会超时,不过800+ms就跑过了。。。

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair<int, int> 
#define FAST ios::sync_with_stdio(false)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1005;
using namespace std;

char s[maxn][maxn], s2[maxn][maxn];
int l[maxn][maxn], r[maxn][maxn], u[maxn][maxn], d[maxn][maxn];
int len[maxn][maxn];

struct node{
	int x, y, s;
	node(){}
	node(int tx, int ty, int ts){
		x = tx, y = ty, s = ts;
	}
} f[maxn*maxn];

int main()
{
	int n, m; scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			s2[i][j] = '.';
		}
	}
	for(int i = 1; i <= n; i++) scanf(" %s", s[i] + 1);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] == '*') l[i][j] = l[i][j-1] + 1;
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = m; j >= 1; j--){
			if(s[i][j] == '*') r[i][j] = r[i][j+1] + 1;
		}
	}
	for(int j = 1; j <= m; j++){
		for(int i = 1; i <= n; i++){
			if(s[i][j] == '*') u[i][j] = u[i-1][j] + 1;
		}
	}
	for(int j = 1; j <= m; j++){
		for(int i = n; i >= 1; i--){
			if(s[i][j] == '*') d[i][j] = d[i+1][j] + 1;
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] == '*'){
				len[i][j] = min(l[i][j], min(r[i][j], min(u[i][j], d[i][j])));
				len[i][j]--;
				if(!len[i][j]) continue;
				int t = len[i][j];
				f[++cnt] = node(i, j, len[i][j]);
				for(int k = i - len[i][j]; k <= i + len[i][j]; k++) s2[k][j] = '*';
				for(int k = j - len[i][j]; k <= j + len[i][j]; k++) s2[i][k] = '*';
			}
		}
	}
	bool flag = true;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] != s2[i][j]) flag = false;
		}
	}
	if(!flag) puts("-1");
	else{
		printf("%d\n", cnt);
		for(int i = 1; i <= cnt; i++){
			printf("%d %d %d\n", f[i].x, f[i].y, f[i].s);
		}
	}
	return 0;
}

 

参考了别人代码,想了一个优化,使得复杂度在O(n*m*C)

类似区间求和的思想,预处理的时候+1/-1操作

用两个二维数组W和S来求出前缀和,再查询就行了

优化完405ms,当然,这是数据的问题,否则优化的时间不会是常数级的

 

AC Code2

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair<int, int> 
#define FAST ios::sync_with_stdio(false)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1005;
using namespace std;

char s[maxn][maxn], s2[maxn][maxn];
int l[maxn][maxn], r[maxn][maxn], u[maxn][maxn], d[maxn][maxn];
int len[maxn][maxn], W[maxn][maxn], S[maxn][maxn];

struct node{
	int x, y, s;
	node(){}
	node(int tx, int ty, int ts){
		x = tx, y = ty, s = ts;
	}
} f[maxn*maxn];

int main()
{
	int n, m; scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++) scanf(" %s", s[i] + 1);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] == '*') l[i][j] = l[i][j-1] + 1;
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = m; j >= 1; j--){
			if(s[i][j] == '*') r[i][j] = r[i][j+1] + 1;
		}
	}
	for(int j = 1; j <= m; j++){
		for(int i = 1; i <= n; i++){
			if(s[i][j] == '*') u[i][j] = u[i-1][j] + 1;
		}
	}
	for(int j = 1; j <= m; j++){
		for(int i = n; i >= 1; i--){
			if(s[i][j] == '*') d[i][j] = d[i+1][j] + 1;
		}
	}
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] == '*'){
				len[i][j] = min(l[i][j], min(r[i][j], min(u[i][j], d[i][j])));
				len[i][j]--;
				if(!len[i][j]) continue;
				int t = len[i][j];
				f[++cnt] = node(i, j, len[i][j]);
				W[i][j-t]++, W[i][j+t+1]--;
				S[i-t][j]++, S[i+t+1][j]--;
			}
		}
	}
	bool flag = true;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			W[i][j] += W[i][j-1], S[i][j] += S[i-1][j];
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(s[i][j] == '*' && !W[i][j] && !S[i][j]) flag = false;
		}
	}
	if(!flag) puts("-1");
	else{
		printf("%d\n", cnt);
		for(int i = 1; i <= cnt; i++){
			printf("%d %d %d\n", f[i].x, f[i].y, f[i].s);
		}
	}
	return 0;
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值