Codeforces 487D. Conveyor Belts 分块+DP

题意:

有一个n×m的地图,上面有三种符号 分别表示向上,向左,向右

有两种操作,A X Y询问从一个点(X,Y)开始最终会走到哪个点或者死循环 , C X Y ch 表示将地图上(X,Y)的符号换成ch

考虑到没有向下的操作,那么陷入死循环的情况只有一种可能即‘>‘ ‘<‘

用分块操作,分成sqrt(n)块,用DP预处理每一块中的点可以到哪个点,-1表示这个点死循环

对于操作A,如果这个点移动到了所在的块的边界处,则输出。否则递归的输出上面的一块

对于操作C,重新对点所在的块进行DP,由于C操作最多只有1W次,又进行了分块处理,所以不会太慢。。。。

D. Conveyor Belts

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Automatic Bakery of Cyberland (ABC) recently bought an n?×?m rectangle table. To serve the diners, ABC placed seats around the table. The size
of each seat is equal to a unit square, so there are 2(n?+?m) seats in total.

ABC placed conveyor belts on each unit square on the table. There are three types of conveyor belts: "^", "<"
and ">". A "^" belt can bring
things upwards. "<" can bring leftwards and ">"
can bring rightwards.

Let‘s number the rows with 1 to n from top to bottom,
the columns with 1 to m from left to right. We consider
the seats above and below the top of the table are rows 0 and n?+?1 respectively.
Also we define seats to the left of the table and to the right of the table to be column 0and m?+?1.
Due to the conveyor belts direction restriction there are currently no way for a diner sitting in the row n?+?1 to be served.

Given the initial table, there will be q events in order. There are two types of events:

  • "A x y" means, a piece of bread will appear at
    row x and column y (we will denote such position
    as (x,?y)). The bread will follow the conveyor belt, until arriving at a seat of a diner. It is possible that the bread gets stuck in an infinite
    loop. Your task is to simulate the process, and output the final position of the bread, or determine that there will be an infinite loop.
  • "C x y c"
    means that the type of the conveyor belt at (x,?y) is changed to c.

Queries are performed separately meaning that even if the bread got stuck in an infinite loop, it won‘t affect further queries.

Input

The first line of input contains three integers nm and q (1?≤?n?≤?105,?1?≤?m?≤?10,?1?≤?q?≤?105),
separated by a space.

Next n lines, each line contains m characters,
describing the table. The characters can only be one of "<^>".

Next q lines, each line describes an event. The format is "C
x y c" or "A x y" (Consecutive elements are separated by a space). It‘s guaranteed that 1?≤?x?≤?n,?1?≤?y?≤?mc is
a character from the set "<^>".

There are at most 10000 queries of "C" type.

Output

For each event of type "A", output two integers txty in
a line, separated by a space, denoting the destination of (x,?y) is (tx,?ty).

If there is an infinite loop, you should output tx?=?ty?=??-?1.

Sample test(s)

input

2 2 3
>>
^^
A 2 1
C 1 2 <
A 2 1

output

1 3
-1 -1

input

4 5 7
><<^<
^<^^>
>>>^>
>^>>^
A 3 1
A 2 2
C 1 4 <
A 3 1
C 1 2 ^
A 3 1
A 2 2

output

0 4
-1 -1
-1 -1
0 2
0 2

Note

For the first sample:

If the bread goes from (2,?1), it will go out of the table at (1,?3).

After changing the conveyor belt of (1,?2) to "<",
when the bread goes from (2,?1) again, it will get stuck at "><",
so output is (?-?1,??-?1).

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn=100100;

int n,m,q;
int kuai,kn;
char str[maxn][12];
int dp[maxn][12];
/// dp[y][z]=w: 在第x块中第y行第z列 走到了w号格子 

int dfs(int k,int x,int y)
{
	if(dp[x][y]) return dp[x][y];

	if(str[x][y]=='^')
	{
		int nx=x-1,ny=y;
		if(nx<1+(k-1)*kuai)
		{
			dp[x][y]=nx*(m+2)+ny;
		}
		else
		{
			dp[x][y]=dfs(k,nx,ny);
		}
	}
	else if(str[x][y]=='>')
	{
		int nx=x,ny=y+1;
		if(ny==m+1)
		{
			dp[x][y]=nx*(m+2)+ny;
		}
		else if(str[nx][ny]=='<')
		{
			dp[x][y]=-1;
			dp[nx][ny]=-1;
		}
		else
		{
			dp[x][y]=dfs(k,nx,ny);
		}
	}
	else if(str[x][y]=='<')
	{
		int nx=x,ny=y-1;
		if(ny==0)
		{
			dp[x][y]=nx*(m+2)+ny;
		}
		else if(str[nx][ny]=='>')
		{
			dp[x][y]=-1;
			dp[nx][ny]=-1;
		}
		else
		{
			dp[x][y]=dfs(k,nx,ny);
		}

	}
	return dp[x][y];
}

/// 在第几块中
void getPOS(int x)
{
	/// Range of Row
	/// 1+(x-1)*kuai ~ x*kuai
	for(int r=1+(x-1)*kuai;r<=min(x*kuai,n);r++)
	{
		for(int c=1;c<=m;c++)
		{
			dfs(x,r,c);
		}
	}
}

void changeIt(int k,int x,int y,char c)
{

	for(int r=1+(k-1)*kuai;r<=min(k*kuai,n);r++)
		for(int c=1;c<=m;c++)
			dp[r][c]=0;
	str[x][y]=c;
	getPOS(k);
}

int FindIt(int k,int x,int y)
{
	if(dp[x][y]==-1) return -1;
	if(k==1) return dp[x][y];
	int temp=dp[x][y];
	int nx=temp/(m+2); int ny=temp%(m+2);
	if(ny!=0&&ny!=m+1) return FindIt(k-1,nx,ny);
	return temp;
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		scanf("%s",str[i]+1);

	kuai=int(sqrt(n))+1;
	kn=n/kuai;
	if(n%kuai) kn++;

	for(int i=1;i<=kn;i++)
		getPOS(i);

	char cmd[20],ch[10];
	int X,Y;

	while(q--)
	{
		scanf("%s",cmd);
		if(cmd[0]=='A')
		{
			scanf("%d%d",&X,&Y);
			int nn=(X-1)/kuai+1;
			int ID = FindIt(nn,X,Y);
			if(ID>=0) printf("%d %d\n",ID/(m+2),ID%(m+2));
			else puts("-1 -1");
		}
		else if(cmd[0]=='C')
		{
			scanf("%d%d%s",&X,&Y,ch);
			int nn=(X-1)/kuai+1;
			changeIt(nn,X,Y,ch[0]);
		}
	}
	return 0;
}
时间: 2024-11-03 06:52:29

Codeforces 487D. Conveyor Belts 分块+DP的相关文章

CodeForces 487D Conveyor Belts

题意: n*m(10^5*10)的棋盘  每个格子有个箭头表示行走方向  有q(10^5)个操作  更改操作即改变某个位置的箭头  更改最多10^4次  查询操作即询问从(x,y)位置开始走最后走到哪  或者  死循环 思路: 我们发现n大m小  联想到可能3进制状压什么的  如果不更新明显dp一下就好  更新少  联想到分块搞 因为分块有个很好的性质  "走出这一块,就不归我这一块管了"  也就是更新只影响一块 假设分块大小为sqrt(n)  那么更新的复杂度就是 O(sqrt(n)

Codeforces 360C Levko and Strings dp

题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t对应位置的k个子串字典序>s #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace std; #

CodeForces 30C Shooting Gallery 简单dp

题目链接:点击打开链接 给定n个气球 下面n行 x y t val 表示气球出现的坐标(x,y) 出现的时刻t,气球的价值val 枪每秒移动1个单位的距离 问: 射击的最大价值,开始时枪瞄准的位置任意. 思路: dp一下.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3

codeforces 149D - Coloring Brackets (区间dp)

题目大意: 给出一组合法的括号. 括号要么不涂颜色,要么就涂上红色或者绿色. 匹配的括号只能有一个有颜色. 两个相邻的括号不能有相同的颜色. 思路分析: 因为是一个合法的括号序列. 所以每个括号与之匹配的位置是一定的. 那么就可以将这个序列分成两个区间. (L - match[L] )  (match[L]+1, R) 用递归先处理小区间,再转移大区间. 因为条件的限制,所以记录区间的同时,还要记录区间端点的颜色. 然后就是一个递归的过程. #include <cstdio> #include

CodeForces 55D Beautiful numbers 数位DP+数学

题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除. 因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520 现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e 要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,

Codeforces 833B 线段树优化 dp

Codeforces  833B  The Bakery 题意: n 个数要分成 k 块,每块的价值是其不同数的个数,问价值和最大是多少. tags: dp[i][j]表示前 j 个数分成 i 块的最大权值和,转移: dp[i][j] = max( dp[i-1][k] + val[k+1][j] ) , k是 1~j . 但这个过程其实并不好转移,要利用累加的特点,用线段树进行优化 (感觉我不看题解是想不到的,2333) 大概就是,对于第 i 层,我们假定已经知道了第 i-1 层,也就是求出了

Codeforces 803E--Roma and Poker (DP)

原题链接:http://codeforces.com/problemset/problem/803/E 题意:给一个n长度的字符串,其中'?'可以替换成'D'.'W'.'L'中的任意一种,'D'等价于0, 'W'等价于1.'L'等价于-1.输出所有'?'被替换掉后,W和L的数目之差为k,且任意一个[1, i]的子串中W和L数目之差不能等于k. 思路:用DP做.定义bool dp[i][j]代表前i个字符W和L数目之差为j, -k<=j<=k(在数组中范围为[0, 2*k]),那么当str[i]

codeforces 825F F. String Compression dp+kmp找字符串的最小循环节

/** 题目:F. String Compression 链接:http://codeforces.com/problemset/problem/825/F 题意:压缩字符串后求最小长度. 思路: dp[i]表示前i个字符需要的最小次数. dp[i] = min(dp[j]+w(j+1,i)); (0<=j<i); [j+1,i]如果存在循环节(自身不算),那么取最小的循环节x.w = digit((i-j)/x)+x; 否则w = i-j+1; 求一个区间最小循环节: 证明:http://w