TGUACM Round #5(div 2)

A - City Game

大致题意

给出一个矩阵, 矩阵中F的位置代表可以使用, R代表已经被占用, 现在要从矩阵中选出最大的子矩阵, 要求子矩阵中的所有元素均为F

分析

参考上周的F题, 本题使用同样的方法, 用n^3过了, 由于n是1000, 使用了一秒多. 据说本题使用dp更为容易, 但能力所限, 暴力即可. 另外本题同样使用了前缀和数组(毕竟和上周的方法类似嘛), 逐渐发现前缀和数组的强大之处

代码实现

#include<iostream>
#include<limits.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 1010;

int k, m, n;
int mapp[MAXN][MAXN];

void printmap()
{
	for(int i=1; i<=m; i++)
	{
		for(int j=1; j<=n; j++)
		{
			printf("%d ", mapp[i][j]);
		}
		cout << endl;
	}
}

int main(void)
{
	scanf("%d", &k);
	while(k--)
	{
		scanf("%d %d", &m, &n);
		memset(mapp, 0, sizeof(mapp));
		
		char c;
		for(int i=1; i<=m; i++)
		{
			for(int j=1; j<=n; j++)
			{
				while(c!='R'&&c!='F')	scanf("%c", &c);
				
				if(c=='R')	mapp[i][j] = 1;
				else	mapp[i][j] = 0;
				
				mapp[i][j] += mapp[i - 1][j];
				c = ' ';
			}
		}
//		printmap();
		
		int ans = INT_MIN;
		for(int i=1; i<=m; i++)
		{
			for(int j=i; j<=m; j++)
			{
				int last = 0;
				for(int k=1; k<=n; k++)
				{
					if(mapp[j][k]-mapp[i-1][k]==0)
					{
						last += (j-i+1);
					}
					else
					{
						last = 0;
					}
					if(last>ans)	ans = last;
				}
			}
		}
		
		cout << ans*3 << endl;
	}
	
	return 0;
}

收获与反思

  1. 前缀和数组真好用
  2. 输入字符时, 不要试图使用getchar()来区分空格换行等, 不然会死得很莫名其妙(ban了)
  3. 其他就是memset原来可以对二维数组使用~

B - Sliding Window

大致题意

给出一组数, 给出一个窗口长度, 要求把这个窗口在数组上从前往后依次扫描一遍, 每次输出其中的最大值和最小值

分析

n是10^6, (我居然也会开始分析时间复杂度了(/ω\)) 因此要么O(n)要么O(nlogn), 第一想法是使用优先队列, 后来发现STL中的优先队列并不能得到优先值最高的元素, 只会把它输出, 因此改用单调队列来做(与正常的队列的思路, 代码什么的还是蛮不一样的)

代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 1000100;

int a[N], q[N];

int n, k;


int main(void)
{
	cin >> n >> k;
	for(int i=0; i<n; i++)	scanf("%d", &a[i]);
	
	int front=0, back=-1;
	for(int i=0; i<n; i++)
	{
		if(q[front] < i-k+1)	front ++;
		
		while(back>=front && a[q[back]]>a[i])	back --;
		q[++ back] = i;
		if(i>=k-1)	printf("%d ", a[q[front]]);
	}
	printf("\n");
	front = 0, back = -1;
	for(int i=0; i<n; i++)
	{
		if(q[front] < i-k+1)	front ++;
		
		while(back>=front && a[q[back]]<a[i])	back --;
		q[++ back] = i;
		if(i>=k-1)	printf("%d ", a[q[front]]);
	}
	
	
	return 0;
}

(代码基本照搬自题解视频, 应该算是一道模板题目)

收获与反思

  1. 逐步接触STL和其中的各个函数, 越发觉得, 理解数据结构是一回事, 但编程比赛中不可能自己去实现这些较为简单的数据结构, 因此学会如何使用STL是非常非常必要的.
  2. 本题的单调队列一开始看完代码仍然没有理解. 中午睡了一觉突然灵光一现, 懂得了其中的思想. 其中一开始最难以理解的一点是为什么有的元素在运算过程中丢掉了, 后来发现, 丢掉的这些元素, 并不可能成为我要输出的对象, 比如我要输出最小值的时候, 如果当前队列里是1 3 5, 之后要入队的元素是2, 那么也就是说当前窗口下, 3不可能是我要输出的最小元素(2在3后面), 所以3就可以直接替换成2, 这就是单调队列最重要的思想.
  3. 这种单调队列的实现, 显然(大概…)并不能使用STL来实现, 而是要自己设置数组, 实现元素的替换插入之类的.
  4. 单调队列里面所储存的是原有数组中当前元素的下标, 目的 (大概) 是弹出队列首元素时, 可以根据这个下标判断当前窗口是否已经离开这个位置, 如果这里没有看懂还是要细细体会, 会发现妙啊!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值