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;
}