CodeForces 182E Wooden Fence

题目意思是说,一个人要修建篱笆,找了一家木篱笆公司买木板。这个公司若干种类的木板,并且仓库足够大,所以每种种类的木板数量可以看做无限大。

现在这个人从这个公司买回若干种类的木板若干块。

一块木板的种类由它的长和宽决定。不同的长宽表示不同的木板种类。

现在这个人想尽可能构建出漂亮的篱笆,漂亮的篱笆,有两个条件

1 不允许有连续两个以上的相同种类的木板

2 下一块模板的长度要等于上一块木板的宽度

木板可以旋转,长宽互换。

现在给出木板的种类数目(块数)和要构建篱笆的长度。问有多少种排列方式可以构建出漂亮的篱笆。

最后的答案非常大,需要mod   1e9+7

 

注意下第三组样例,一开始我以为第三组样例中两块2 1的木板不能放在一起。

仔细读了题目以后发现,输入的N代表的是木板的种类,这两块木板出现在下面的输入数据中,说明这两块木板应该看做不同种类的木板,只有一块木板旋转以后才看做相同的木板。

然后就可以用DP做了。

构建一个DP数组【i】【j】代表当前已经构建了长度为i的篱笆,最后一块木板是j的方案总数。

开始dp数组清零

开始的时候处理每一块木板,然后对应的木板加1;然后开始循环。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<functional>
#include<algorithm>
#define Mod 1000000007
using namespace std;
int n,l;
long long ans;//木板可以旋转,数组要开两倍
int a[230],b[230];//a代表每一块木板的长度,b代表每一块木板的宽度
long long dp[3105][230];//数组要开大点,尤其第一维,会超过L的限制
int main()
{
	int i,j,k;
	while(scanf("%d%d",&n,&l)!=EOF)
	{
		ans=0;
		memset(dp,0,sizeof(dp));//清零
		for(i=0;i<n;i++)
		{
			scanf("%d%d",&a[i],&b[i]);
			dp[a[i]][i]++;//对应木板初始化为1
			if(a[i]!=b[i])//长宽不一样的木板可以旋转
			{
				a[i+n]=b[i];//旋转以后处理
				b[i+n]=a[i];
				dp[a[i+n]][i+n]++;
			}
		}
		for(i=1;i<=l;i++)//状态转移,从当前长度i加上新木板转移状态i+a【k】
		{
			for(j=0;j<2*n;j++)//循环宽度木板的种类
			{
				if(!dp[i][j])
					continue;
				for(k=0;k<2*n;k++)//循环长度木板的种类
				{
					if(j%n!=k%n&&b[j]==a[k])//木板种类不相同且a【k】木板可以接在b【j】木板后面
						dp[i+a[k]][k]=(dp[i+a[k]][k]+dp[i][j])%Mod;//状态转移
				}
			}
		}
		for(i=0;i<2*n;i++)//最后只需要计数长度为l的方案总数
			ans=(ans+dp[l][i])%Mod;
		printf("%d\n",ans);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值