P7683 [COCI2008-2009#5] KRUSKA

Posted Mars_Dingdang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P7683 [COCI2008-2009#5] KRUSKA相关的知识,希望对你有一定的参考价值。

洛谷上这道题的第一篇题解。上海加油。

题目大意

Aladdin 已经厌倦了宫殿里的生活。他有一份稳定的工作,他的妻子 Jasmine 和孩子们都在路上,生活变得单调。在这一切的驱使下,他决定在安顿下来之前再进行一次冒险。他决定找到 Golden Pear,这是一件极为珍贵的传奇文物,至今无人能找到。

Aladdin 正在寻找的沙漠可以被看作是一个 \\(n×n\\) 的网格。行和列从上到下、从左到右编号为 \\(1\\)\\(N\\)。沙漠中的网格里一共有 \\(M\\) 个巫师,他们以一种不同寻常的方式帮助 Aladdin 完成任务。

Aladdin 星期一在沙漠的左上角 \\((1,1)\\) 开始他的任务并面朝右。他的动作包括重复这些步骤:

  • 如果当前的网格里有一个醒着的巫师,那么 Aladdin 会根据巫师说的话向左或向右转 \\(90\\) 度。
  • 如果向前走会把 Aladdin 带出沙漠,他会转过 \\(180\\) 度。
  • Aladdin 向前移动了一格,这将花费他一天的时间。

对于每个巫师,我们都知道他的位置和一周中每一天的活动计划。每个巫师的日程表是一个由七个字母(仅包含 LRS)组成的字符串,每个字符告诉我们巫师在一周中的某一天(从星期一开始)做什么。字母 L 表示 Aladdin 将在这一天被告知向左转,R 表示 Aladdin 将在这一天被告知向右转,而 S 表示巫师那天正在睡觉。

一个古老的预言说,在改变 \\(K\\) 次方向(通过步骤 \\(1\\) 和步骤 \\(2\\))后,Aladdin 会找到 Golden Pear。根据古老的预言,写一个程序来计算冒险将持续多少天。

大体思路

按照题意,定义一个状态为 \\((x,y,dir,day)\\),表示当前位置 \\((x,y)\\) 在星期 \\(day\\) 被访问,方向为 \\(dir\\),其中 \\(x,y\\le 200\\)\\(dir=\\0,1,2,3\\\\)\\(day=\\0,1,2,3,4,5,6\\\\)。因此,总的状态数为 \\(200^2\\times 4\\times 7≈10^6\\)。所以,我们完全可以用数组直接存储每一个状态。

\\(turns[x,y,dir,day]\\) 表示上一次在星期 \\(day\\)\\(dir\\) 方向来到 \\((x,y)\\) 时转向的次数,而 \\(date[x,y,dir,day]\\) 则表示上一次在星期 \\(day\\)\\(dir\\) 方向来到 \\((x,y)\\) 时的天数。设当前转向次数为 \\(k\\),天数为 \\(ans\\),那么,从上一次访问到这一次访问的循环,转向的次数为 \\(\\Delta k=k-turns[x,y,dir,day]\\),循环的天数为 \\(\\Delta t=ans - date[x,y,dir,day]\\)

由于距离目标 \\(K\\) 次转向还有 \\(K-k\\) 次,可以完成的完整的循环次数为 \\(times=\\left\\lfloor\\dfracK-k\\Delta k\\right\\rfloor\\)。那么,可以直接将转向次数增加 \\(\\Delta k\\times times\\),天数增加 \\(\\Delta t \\times times\\)。然后,在对 \\(date,turns\\) 用目前状态的 \\(ans,k\\) 进行更新即可。

具体实现时,还需要在永久循环的开头判断 LR 以及边界的转向,并调整 \\(dir,k\\) 等。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re int ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair<int, int> PII;
const int maxn = 205;
namespace IO_ReadWrite 
	#define re register
	#define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++)
	char _buf[1<<21], *p1 = _buf, *p2 = _buf;
	template <typename T>
	inline void read(T &x)
		x = 0; re T f=1; re char c = gg;
		while(c > 57 || c < 48)if(c == \'-\') f = -1;c = gg;
		while(c >= 48 &&c <= 57)x = (x<<1) + (x<<3) + (c^48);c = gg;
		x *= f;return;
	
	inline void ReadChar(char &c)
		c = gg;
		while(!isalpha(c)) c = gg;
	
	template <typename T>
	inline void write(T x)
		if(x < 0) putchar(\'-\'), x = -x;
		if(x > 9) write(x/10);
		putchar(\'0\' + x % 10);
	
	template <typename T>
	inline void writeln(T x)write(x); putchar(\'\\n\');

using namespace IO_ReadWrite;
int dx[4] = 0, 1, 0, -1,
	dy[4] = 1, 0, -1, 0;//right, down, left, up
int N, M, K, turns[maxn][maxn][4][8];
char mp[maxn][maxn][8];
ll date[maxn][maxn][4][8];
int main () 
	scanf("%d%d%d", &N, &K, &M);
	rep(i, 1, M) 
		int x, y;
		scanf("%d%d", &x, &y);
		scanf("%s", mp[x][y]);
	
	ll ans = 0;
	int x = 1, y = 1, dir = 0, day = 0, k = 0;
	while(1) 
		if(mp[x][y][day] == \'L\') dir = (dir + 3) % 4, k ++;
		if(mp[x][y][day] == \'R\') dir = (dir + 1) % 4, k ++;
		int nx = x + dx[dir], ny = y + dy[dir];
		if(nx < 1 || nx > N || ny < 1 || ny > N) dir = (dir + 2) % 4, k ++;
		if(date[x][y][dir][day]) 
			int newK = k - turns[x][y][dir][day];
			int left = K - k;
			ans += (left / newK) * (ans - date[x][y][dir][day]);
			k += (left / newK) * newK;
		
		date[x][y][dir][day] = ans;
		turns[x][y][dir][day] = k;
		if(k >= K) break;
		x = x + dx[dir], y = y + dy[dir];
		ans ++;
		if(++day >= 7) day = 0;
	
	writeln(ans);
	return 0;

以上是关于P7683 [COCI2008-2009#5] KRUSKA的主要内容,如果未能解决你的问题,请参考以下文章

题解 洛谷P6413 [COCI2008-2009#3] NAJKRACI

[COCI]coci2015/2016 nekameleoni

题解Dvoniz [COCI2011]

BZOJ3743[Coci2015]Kamp 树形DP

@COCI 2016/2017 Round 3@ Meksikanac

[COCI2017-2018#6] Alkemija