Codeforces Round #355 (Div. 2) Vanya and Treasure

这是一道很显然的DP题目,状态转移在题目中也很直接,就是从k-1到k,然而如果count[k-1]*cnt[k],那么时间复杂度就会很大,本来的复杂度应该是O(p*n*n*m*m),用DP的话会很TLE,看了大牛的解释后,是在p<sqrt(mn)时候用DP,之后如果p>sqrt(nm)的话就用BFS,这样用均摊分析可以计算其时间复杂度(后边我打算写一篇关于均摊分析的博文)。

#include  <iostream>
#include  <cstdio>
#include  <cstring>
#include  <vector>
#include  <queue>
#include  <cmath>
#include  <algorithm>
#define X first
#define Y second
#define mp make_pair
#define Pair pair<int,pair<int,int> >
using namespace std;
const int INF=99999999;
const int maxn=305;
const int maxp=maxn*maxn;
const int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0};
int n,m,p,a[maxn][maxn],dp[maxn][maxn];
int d[maxn][maxn];
struct Node
{
	int x,y;
	Node(int x,int y)
	{
		this->x=x;
		this->y=y;
	}
};
vector<Pair > lst;
vector<Node> G[maxp];
bool in_range(int x,int y)
{
	if(x>=1&&x<=n&&y>=1&&y<=m)
		return true;
	return false;
}
int main()
{
	for(int i=0;i<maxn;i++)
		for(int j=0;j<maxn;j++)
			dp[i][j]=INF;
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			G[a[i][j]].push_back(Node(i,j));
			if(a[i][j]==1)
			{
				dp[i][j]=(i-1)+(j-1);
			}
		}
	}
	for(int k=2;k<=p;k++)
	{
		if(G[k].size()*G[k-1].size()<n*m)
		{
			for(int i=0;i<G[k].size();i++)
			{
				Node& p1=G[k][i];
				for(int j=0;j<G[k-1].size();j++)
				{
					Node& p2=G[k-1][j];
					int dist=abs(p1.x-p2.x)+abs(p1.y-p2.y);
					dp[p1.x][p1.y]=min(dp[p1.x][p1.y],dp[p2.x][p2.y]+dist);
				}
			}
		}
		else
		{
			for(int i=0;i<=n;i++)
				for(int j=0;j<=m;j++)
					d[i][j]=-1;
			queue<Pair > que;
			while(!que.empty())
				que.pop();
			lst.clear();
			for(int i=0;i<G[k-1].size();i++)
			{
				int x=G[k-1][i].x;
				int y=G[k-1][i].y;
				lst.push_back(mp(dp[x][y],mp(x,y)));
			}
			int cnt(0),sum(G[k].size());
			sort(lst.begin(),lst.end());
			for(int i=0;i<lst.size();i++)
			{
				que.push(lst[i]);
				d[lst[i].Y.X][lst[i].Y.Y]=lst[i].X;
			}
			while(!que.empty())
			{
				Pair temp=que.front();
				que.pop();
				for(int i=0;i<4;i++)
				{
					int tx=temp.Y.X+dx[i];
					int ty=temp.Y.Y+dy[i];
					if(in_range(tx,ty))
					{
						if(d[tx][ty]==-1||d[tx][ty]>temp.X+1)
						{
							d[tx][ty]=temp.X+1;
							que.push(mp(temp.X+1,mp(tx,ty)));
							if(a[tx][ty]==k)
							{
								dp[tx][ty]=min(dp[tx][ty],temp.X+1);
							}
						}
					}
				}
			}
		}
	}
	printf("%d\n",dp[G[p][0].x][G[p][0].y]);
	return 0;
}

  

时间: 2024-08-05 15:20:52

Codeforces Round #355 (Div. 2) Vanya and Treasure的相关文章

Codeforces Round #355 (Div. 2) Vanya and Label

这道题很注重转化,其实质其实是将字符串每个字符转换成对应的数字后,按照6位进行二进制转化,然后统计0出现的次数,0&1=0,1&0=1,0&0=0,有些人用了快速幂,实际上这完全没有必要,但是一定要用long long. #include <iostream> #include <cstdio> #include <string> using namespace std; const long long MOD=1e9+7; string s;

Codeforces Round #355 (Div. 2) D. Vanya and Treasure 分治暴力

D. Vanya and Treasure Vanya is in the palace that can be represented as a grid n?×?m. Each room contains a single chest, an the room located in the i-th row and j-th columns contains the chest of type aij. Each chest of type x?≤?p?-?1 contains a key

Codeforces Round #355 (Div. 2) C

Description While walking down the street Vanya saw a label "Hide&Seek". Because he is a programmer, he used & as a bitwise AND for these two words represented as a integers in base 64 and got new word. Now Vanya thinks of some string s 

Codeforces Round #355 (Div. 2) B

Description Vanya smashes potato in a vertical food processor. At each moment of time the height of the potato in the processor doesn't exceed h and the processor smashes k centimeters of potato each second. If there are less than k centimeters remai

Codeforces Round #482 (Div. 2) :B - Treasure Hunt

题目链接:http://codeforces.com/contest/979/problem/B 解题心得: 这个题题意就是三个人玩游戏,每个人都有一个相同长度的字符串,一共有n轮游戏,每一轮三个人必须改变自己字符串中的一个字母,最后得分就是字符串中出现字符最多的字母的次数. 感觉这个题从题目描述到做法都像一个脑筋急转弯.主要明白一点,如果一个数要变回自己要怎么变.自己->其他->自己.自己->其他->其他->自己,推几个特例很容易就出来了. 1 #include <b

Codeforces Round #355 (Div. 2)

A 弯腰 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 #include<stack> 6 #include<algorithm> 7 using namespace std; 8 #define clc(a,b) memset(a,b,sizeof(a)) 9 #define inf 0x3f3f3f3f 10 cons

暴力/进制转换 Codeforces Round #308 (Div. 2) C. Vanya and Scales

题目传送门 1 /* 2 题意:问是否能用质量为w^0,w^1,...,w^100的砝码各1个称出重量m,砝码放左边或在右边 3 暴力/进制转换:假设可以称出,用w进制表示,每一位是0,1,w-1.w-1表示砝码与物品放在一起,模拟判断每位是否ok 4 详细解释:http://blog.csdn.net/u011265346/article/details/46556361 5 总结:比赛时压根没往进制去想,连样例也不知道是怎么回事..中文不行啊:( 6 */ 7 #include <cstdi

水题 Codeforces Round #308 (Div. 2) A. Vanya and Table

题目传送门 1 /* 2 水题:读懂题目就能做 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <vector> 10 #include <string> 11 #include <queue> 12 #include

数学 Codeforces Round #308 (Div. 2) B. Vanya and Books

题目传送门 1 /* 2 水题:求总数字个数,开long long竟然莫名其妙WA了几次,也没改啥又对了:) 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <vector> 10 #include <string> 11 #inc