【BZOJ1210】[HNOI2004]邮递员 插头DP+高精度

【BZOJ1210】[HNOI2004]邮递员

Description

Smith在P市的邮政局工作,他每天的工作是从邮局出发,到自己所管辖的所有邮筒取信件,然后带回邮局。他所管辖的邮筒非常巧地排成了一个m*n的点阵(点阵中的间距都是相等的)。左上角的邮筒恰好在邮局的门口。 Smith是一个非常标新立异的人,他希望每天都能走不同的路线,但是同时,他又不希望路线的长度增加,他想知道他有多少条不同的路线可走。【任务描述】你的程序需要根据给定的输入,给出符合题意的输出:? 输入包括点阵的m和n的值;? 你需要根据给出的输入,计算出Smith可选的不同路线的总条数;

Input

只有一行。包括两个整数m, n(1 <= m <= 10, 1 <= n <= 20),表示了Smith管辖内的邮筒排成的点阵。

Output

只有一行,只有一个整数,表示Smith可选的不同路线的条数。

Sample Input

2 2
说明:该输入表示,Smith管辖了2*2的一个邮筒点阵。

Sample Output

2

题解:同1814,只不过需要高精度。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int limit=199917;
int hs[limit];	//队列,存编号
int n,m,k,tot[2];
char str[20];
int state[2][limit];	//state:编号存hash值 dp:编号存dp值
struct Cbig
{
	int v[20],len;
	Cbig() {memset(v,0,sizeof(v)),len=1;}
	inline Cbig operator + (const Cbig &b) const
	{
		Cbig c;
		c.len=max(len,b.len);
		for(int i=1;i<=c.len;i++)
		{
			c.v[i]+=v[i]+b.v[i];
			if(c.v[i]>100000000)	c.v[i]-=100000000,c.v[i+1]++;
		}
		if(c.v[c.len+1])	c.len++;
		return c;
	}
	inline void print()
	{
		printf("%d",v[len]);
		for(int i=len-1;i;i--)	printf("%08d",v[i]);
	}
}ans,dp[2][limit];
inline void upd(int S,Cbig tag)
{
	int pos=S%limit;
	while(hs[pos])
	{
		if(state[k][hs[pos]]==S)
		{
			dp[k][hs[pos]]=dp[k][hs[pos]]+tag;
			return ;
		}
		pos++;
		if(pos==limit)	pos=0;
	}
	hs[pos]=++tot[k];
	state[k][tot[k]]=S;
	dp[k][tot[k]]=tag;
}
int main()
{
	int i,j,t,u,tmp,p,q,x,y;
	int S,T;
	Cbig tag;
	scanf("%d%d",&m,&n);
	if(n==1||m==1)
	{
		puts("1");
		return 0;
	}
	tot[0]=1,state[0][1]=0,dp[0][1].len=dp[0][1].v[1]=1;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			k^=1;
			memset(hs,0,sizeof(hs));
			memset(state[k],0,sizeof(state[k][0])*(tot[k]+1));
			memset(dp[k],0,sizeof(dp[k][0])*(tot[k]+1));
			tot[k]=0;
			for(t=1;t<=tot[k^1];t++)
			{
				S=state[k^1][t],tag=dp[k^1][t];
				y=j<<1,x=y-2,p=(S>>x)&3,q=(S>>y)&3,T=S^(p<<x)^(q<<y);
				if(p==0&&q==0&&j<m&&i<n)	upd(T|(1<<x)|(2<<y),tag);
				if((p==0&&q==1)||(p==1&&q==0))
				{
					if(i<n)	upd(T|(1<<x),tag);
					if(j<m)	upd(T|(1<<y),tag);
				}
				if((p==0&&q==2)||(p==2&&q==0))
				{
					if(i<n)	upd(T|(2<<x),tag);
					if(j<m)	upd(T|(2<<y),tag);
				}
				if(p==2&&q==1)	upd(T,tag);
				if(p==1&&q==2&&i==n&&j==m)	ans=ans+tag;
				if(p==1&&q==1)
				{
					for(tmp=0,u=y+2;u<=m+m&&tmp>=0;tmp+=((T>>u)&1)-((T>>(u+1))&1),u+=2);
					u-=2;
					upd(T^(3<<u),tag);
				}
				if(p==2&&q==2)
				{
					for(tmp=0,u=x-2;u>=0&&tmp>=0;tmp+=((T>>(u+1))&1)-((T>>u)&1),u-=2);
					u+=2;
					upd(T^(3<<u),tag);
				}
			}
		}
		for(t=1;t<=tot[k];t++)	state[k][t]<<=2;
	}
	ans=ans+ans;
	ans.print();
	return 0;
}
时间: 2024-11-08 20:46:07

【BZOJ1210】[HNOI2004]邮递员 插头DP+高精度的相关文章

无聊的 邮递员 插头dp

邮递员想知道,如果他每天都用不同路线走过10×20个点阵邮筒,他必须活过多少个世纪才能走遍所有方案? 7:00 改完T1,开始肝插头dp 7:10 放弃,颓博客 7:20 学习插头dp 7:21 放弃,抄代码 8:30 抄完结构体,负罪感强烈,自打分类讨论 从此 0分:打了一个分类讨论就把它复制粘贴到另一个类似的分类讨论里,改都不改... 0分:为了避免hash出负,行间转移时将状态&full  结果不小心把最高位那个有用的信息舍弃了... 0分:link函数出锅,根本没考虑全所有的情况,也就是

插头dp题表(已完成)

bzoj1814: Ural 1519 Formula 1 bzoj3125: CITY bzoj1210: [HNOI2004]邮递员 bzoj2331: [SCOI2011]地板 bzoj1187: [HNOI2007]神奇游乐园 bzoj2310: ParkII 原文地址:https://www.cnblogs.com/TSHugh/p/8179245.html

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

动态规划之插头DP入门

基于联通性的状态压缩动态规划是一类很典型的状态压缩动态规划问题,因为其压缩的本质并不像是普通的状态压缩动态规划那样用0或者1来表示未使用.使用两种状态,而是使用数字来表示类似插头的状态,因此,它又被称作插头DP. 插头DP本质上是一类状态压缩DP,因此,依然避免不了其指数级别的算法复杂度,即便如此,它依然要比普通的搜索算法快很多. [例]Postal Vans(USACO training 6.1.1) 有一个4*n的矩阵,从左上角出发,每次可以向四个方向走一步,求经过每个格子恰好一次,再回到起

「总结」插头$dp$

集中做完了插头$dp$ 写一下题解. 一开始学的时候还是挺蒙的. 不过后来站在轮廓线$dp$的角度上来看就简单多了. 其实就是一种联通性$dp$,只不过情况比较多而已了. 本来转移方式有两种.逐行和逐格转移. 不过逐行转移因为分类太多所以被舍弃了. 一般的插头$dp$采用逐格转移. 插头表示已经进入当前格子的状态,而并不是将要进入的状态. 状态的表示方式常见的有两种:最小表示法和括号表示法. 括号表示法不如说是广义括号表示法的特殊一种情况,每个插头也就是左右括号就是表示两个相匹配的回路部分,而最

插头dp

对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了. bzoj2331 地板 题目大意:用L型铺地n*m,有一些格子不能铺,求方案数. 思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移. 注意:(1)按四进制好写: (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组. #include<iostream> #include<cstdio> #

poj 1625 Censored!(AC自动机+DP+高精度)

题目链接:poj 1625 Censored! 题目大意:给定N,M,K,然后给定一个N字符的字符集和,现在要用这些字符组成一个长度为M的字符串,要求不包 括K个子字符串. 解题思路:AC自动机+DP+高精度.这题恶心的要死,给定的不能匹配字符串里面有负数的字符情况,也算是涨姿势 了,对应每个字符固定偏移128单位. #include <cstdio> #include <cstring> #include <queue> #include <vector>

【bzoj2764】[JLOI2011]基因补全 dp+高精度

题目描述 在生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对.两个碱基序列能相互匹配,当且仅当它们等长,并且任意相同位置的碱基都是能相互配对的.例如ACGTC能且仅能与TGCAG配对.一个相对短的碱基序列能通过往该序列中任意位置补足碱基来与一个相对长的碱基序列配对.补全碱基的位置.数量不同,都将视为不同的补全方案.现在有两串碱基序列S和T,分别有n和m个碱基(n>=m),问一共有多少种补全方案. 输入 数据包括三行. 第

bzoj 1089 [SCOI2003]严格n元树(DP+高精度)

1089: [SCOI2003]严格n元树 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1250  Solved: 621[Submit][Status][Discuss] Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严格2元树有三个,如下图: 给出n, d,编程数出深度为d的n元树数目. Inp