HDU 5374 Tetris (2015年多校比赛第7场)

1.题目描写叙述:点击打开链接

2.解题思路:本题要求模拟俄罗斯方块游戏。然而比赛时候写了好久还是没过。

后来补题发现原来是第四步的逻辑实现写错了。。。

题目中要求假设一整行能够消除,那么仍然运行该步。否则才回到第一步。可是我的代码却是不论能否够消除,都回到第一步。。

。补题时候还发现一个地方我的理解出错了。。

(可能是我脑洞真的有点大)。题目中说假设一整行能够消除,那么它上面的方格要下落。我的理解是下落的方格要一直降落到第一行或者某个支撑物上,最后发现依照这样写,例子都算不正确==。调试了一下别人的代码才发现是仅仅下落一个。无论它以下是否有支撑物==。或许是非常久都没玩过的原因吧,玩法都忘了。。看来模拟题还是要弄清细节才干动手。否则真是WARush。

本题的实现能够考虑使用常量数组。通过题目描写叙述能够知道一共同拥有7种不同的状态。如果我们以special square为參考,那么每一个状态相对于special square的坐标是能够唯一确定的,最好还是用dx[7][4],dy[7][4]分开表示。另一个技巧。移动或者旋转的时候仅仅须要用一个vector来存储操作后的全部坐标就可以。不必每次真的画到图上,仅仅须要画出终于的位置就可以。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s) memset(s,0,sizeof(s))
#define pb push_back
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N = 15;

int dx[7][4] = { { 0, 0, 1, 1 }, { 0, 0, 0, 0 }, { 0, 1, 2, 3 },
{ 0, 0, 1, 2 }, { 0, 0, 0, 1 }, { 0, 1, 2, 2 }, { 0, 1, 1, 1 }
};
int dy[7][4] = { { 0, 1, 0, 1 }, { 0, 1, 2, 3 }, { 0, 0, 0, 0 },
{ 0, 1, 0, 0 }, { 0, 1, 2, 2 }, { 1, 1, 1, 0 }, { 0, 0, 1, 2 }
};
int first[] = { 0, 1, 3 };//每一类俄罗斯方块的初始状态的编号
int g[N][N];
int a[100000];
vector<P>pos;//用一个vector存储每次操作完的全部坐标
int sx, sy, cur;//(sx,sy)表示special square的坐标。cur表示当前的状态(0~6的某一种)

void init(int id)//初始化状态
{
	pos.clear();
	sx = 4, sy = 9, cur = first[id];
	for (int i = 0; i < 4; i++)
		pos.push_back(P(sx + dx[cur][i], sy + dy[cur][i]));
}

bool inside(int x, int y)
{
	return x >= 1 && x <= 9 && y >= 1 && y <= 12;
}

bool can_move(int dx, int dy)
{
	int len = pos.size();
	for (int i = 0; i < len; i++)
	{
		int nx = pos[i].first + dx, ny = pos[i].second + dy;
		if (!inside(nx, ny) || g[nx][ny])return false;
	}
	return true;
}

bool can_rotate(int type)
{
	if (type == 1)
	{
		int goal = 3 - cur;
		for (int i = 0; i < 4; i++)
		if (!inside(sx + dx[goal][i], sy + dy[goal][i]) || g[sx + dx[goal][i]][sy + dy[goal][i]])return false;
	}
	else if (type == 2)
	{
		int goal = (cur == 6) ? 3 : cur + 1;
		for (int i = 0; i < 4; i++)
		if (!inside(sx + dx[goal][i], sy + dy[goal][i]) || g[sx + dx[goal][i]][sy + dy[goal][i]])return false;
	}
	return true;
}

void move(int dx, int dy)
{
	int len = pos.size();
	for (int i = 0; i < len; i++)
	{
		int nx = pos[i].first + dx, ny = pos[i].second + dy;
		pos[i] = P(nx, ny);
	}
	sx += dx, sy += dy;
}

void rotate(int type)
{
	if (!type)return;
	else if (type == 1)
	{
		cur = 3 - cur;  //更新状态
		int len = pos.size();
		pos.clear();
		for (int i = 0; i < 4; i++)
			pos.push_back(P(sx + dx[cur][i], sy + dy[cur][i]));
	}
	else if (type == 2)
	{
		cur = (cur == 6) ?

3 : cur + 1;
		pos.clear();
		for (int i = 0; i < 4; i++)
			pos.push_back(P(sx + dx[cur][i], sy + dy[cur][i]));
	}
}

void draw()
{
	int len = pos.size();
	for (int i = 0; i < len; i++)
	{
		int x = pos[i].first, y = pos[i].second;
		g[x][y] = 1;
	}
}

void operate(char op, int id)
{
	if (op == 'w')
	{
		if (can_rotate(id))rotate(id);
	}
	else if (op == 'a')
	{
		if (can_move(-1, 0))move(-1, 0);
	}
	else if (op == 's')
	{
		if (can_move(0, -1))move(0, -1);
	}
	else if (op == 'd')
	{
		if (can_move(1, 0))move(1, 0);
	}
}

int can_fall()
{
	int y;
	for (y = 1; y <= 12; y++)
	{
		int ok = 1;
		for (int i = 1; i <= 9; i++)
		if (!g[i][y]){ ok = 0; break; }
		if (ok)return y;
	}
	return 0;
}
int main()
{
	int T;
	int rnd = 0;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		string cmd;
		scanf("%d", &n);
		cin >> cmd;
		me(g); me(a); pos.clear();
		int len = cmd.length();
		int ans = 0, p = 0;
		for (int i = 0; i < n; i++)scanf("%d", &a[i]);
		for (int i = 0; i < n; i++)
		{
			init(a[i]);
			while (1)
			{
				if (p < len)
					operate(cmd[p++], a[i]);
				if (can_move(0, -1)) move(0, -1);//不能下落
				else break;
			}
			draw();//画出终于的位置
			int q, ok;
			while ((q = can_fall())>0)//直到没有完整的一行时才退出
			{
				ans++;
				for (int i = 1; i <= 9; i++)
				{
					g[i][q] = 0;
					for (int j = q + 1; j <= 12; j++)
					if (g[i][j])
						g[i][j - 1] = 1, g[i][j] = 0;  //仅仅下落一格。

。。

不要多想
				}
			}
		}
		printf("Case %d: %d\n", ++rnd, ans);
	}
}
时间: 2024-10-10 18:22:11

HDU 5374 Tetris (2015年多校比赛第7场)的相关文章

HDU5374 Tetris (2015年多校比赛第7场)

1.题目描述:点击打开链接 2.解题思路:本题要求模拟俄罗斯方块游戏,然而比赛时候写了好久还是没过.后来补题发现原来是第四步的逻辑实现写错了...题目中要求如果一整行可以消除,那么仍然执行该步,否则才回到第一步.但是我的代码却是不论是否可以消除,都回到第一步...补题时候还发现一个地方我的理解出错了..(可能是我脑洞真的有点大),题目中说如果一整行可以消除,那么它上面的方格要下落.我的理解是下落的方格要一直降落到第一行或者某个支撑物上,最后发现按照这样写,样例都算不对==.调试了一下别人的代码才

HDU 5399 Too Simple (2015年多校比赛第9场)

1.题目描述:点击打开链接 2.解题思路:本题分情况讨论.比赛时候真是想的太简单了,以为就是(n!)^(cnt-1).最终无限WA.本题有几个特殊情况需要额外判断.首先,如果输入的时候,有某一行不是-1且有两个数映射到同一个数,那么必然无解,ans=0.其次,如果不存在-1,需要从第m个函数一步步映射到第1个函数,检查一下最后是否真的变成了自身映射.最容易想到的情况就是有至少一个-1,那么最后答案就是(n!)^(cnt-1). 3.代码: //#pragma comment(linker, "/

HDU 5411 CRB and Puzzle (2015年多校比赛第10场)

1.题目描写叙述:pid=5411">点击打开链接 2.解题思路:本题实际是是已知一张无向图.问长度小于等于m的路径一共同拥有多少条. 能够通过建立转移矩阵利用矩阵高速幂解决.当中,转移矩阵就是输入时候的邻接矩阵,同一时候多添加最后一列,都置为1.表示从i開始的,长度不超过M的路径的答案总数(最后一行的1~n列为全0行,能够理解为空集),那么把转移矩阵自乘M-1次后就是路径长度为M的转移矩阵(这里的路径长度指的是顶点的个数.顶点=边数+1,因此仅仅须要乘M-1次). 为何便于求和.能够设置

HDU5374 Tetris (2015年多校比赛第7场)大模拟

思路: 先写好了几个函数.旋转,四种操作,判断是否可以进行合并消除 题中有好几处要考虑的细节问题,如 自然下落到底部时不进行合并的判断,而是当自然下落非法时才判断 如果消除一行,这一行上面的所以方块只会下落一行,不存在直接下落到底部的情况 比赛时题意没有理解好,错了这两个地方.. 还有一些写法上的错误,这种左右移动的题目坐标还是要从1开始,方便许多 左右移动,如果非法要复原的时候,复原的操作要与移动操作 完全相反,并且这个范围要从0开始,因为移动的时候可能移动到非法的位置. 赛后看了标程,各种优

HDU 5400 Arithmetic Sequence (2015年多校比赛第9场)

1.题目描述:点击打开链接 2.解题思路:本题利用扫描法解决.根据题意描述,[L,i)和[i,R)区间都构成了等差数列,因此可以实现用L[i],R[i]来维护从i开始向左向右可以延伸的最远长度,如果d1和d2不等,那么答案就是L[i]*R[i]求和,否则就是R[i]求和. 3.代码: //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorit

HDU 5386 Cover (2015年多校比赛第8场)

1.题目描述:点击打开链接 2.解题思路:本题利用逆向思维+贪心法解决.因为题目中已经告诉我们一定存在解,因此可以考虑贪心法的使用.这道题的妙处在于答案和初始矩阵是无关的,只和目标矩阵有关.因为不管初始矩阵长什么样,只要操作一样,加上解的存在性,得到的目标矩阵一定是相同的.接下来就是如何寻找操作序列. 假设最后一步操作执行后,我们得到了目标矩阵,由于所有操作都是对一整行或者一整列进行的,因此肯定有一行或者一列全部相同.这样,我们就可以从目标矩阵出发,逆着这个过程寻找,如果发现某一行或者一列全部相

HDU 5414 CRB and String (2015年多校比赛第10场)

1.题目描写叙述:点击打开链接 2.解题思路:本题要求推断字符串s是否能通过加入若干个字符得到字符串t. 首先,能够知道,s必须是t的一个子串(注意:不是连续子串). 第二.因为插入的新字符和它前面的字符c不同.因此假设t中有cnt个连续的c.那么在s中也必须有cnt个连续的c.因此.仅仅要能够满足这2个条件,就一定能够成功实现转化. 那么该怎样做呢?两者能够结合起来推断,用i,j分别表示s,t串中当前扫描的字符的下标.首先从字符串t開始扫描,看第一个字符c是否连续,一直到不连续为止,那么依据上

HDU 5381 The sum of gcd (2015年多校比赛第8场)

1.题目描述:点击打开链接 2.解题思路:本题利用莫队算法解决.由于是第一次学习这个算法,因此研究了比较长的一段时间才弄懂.首先,莫队算法解决的问题是无修改的离线区间查询问题.该算法实际上是由曼哈顿距离最小生成树演变来的,由于要处理m个区间,可以将这m个区间看做二维平面上的点,那么处理这m个区间就等价于让这m点连通,且总的转移代价最小.这其实就是一个曼哈顿距离最小生成树问题. 经典的曼哈顿距离最小生成树的时间复杂度是O(NlogN),莫队算法的时间复杂度是O(N^1.5).不过本题还有一个地方,

HDU 5407 CRB and Candies (2015年多校比赛第10场)

1.题目描述:点击打开链接 2.解题思路:本题要求LCM(C(n,0), C(n,1),..., C(n,n)),官方题解是转化为求解LCM(1,2,3,...n+1)/(n+1),然而这种做法还是觉得太陌生,不妨试着用学过的唯一分解定理去做. 首先,求这n+1个数的LCM,实际上就是求所有小于n的素数中,对于每一个素数Pi,哪一项的指数最大,然后把他们连乘起来即可得到LCM值.因此,问题转化为确定每一个pi的最大指数.这里要用到Kummer定理来解决,Kummer定理告诉我们这样一个事实:p恰