codeforces 182E Wooden Fence(方案数DP)【模板】

Vasya has recently bought some land and decided to surround it with a wooden fence.

He went to a company called "Wooden board" that produces wooden boards for fences. Vasya read in the catalog of products that the company has at its disposal ndifferent types of wood. The company uses the i-th type of wood to produce a board of this type that is a rectangular ai by bi block.

Vasya decided to order boards in this company and build a fence from them. It turned out that the storehouse of the company is so large that Vasya can order arbitrary number of boards of every type. Note that Vasya is allowed to turn the boards as he builds the fence. However, Vasya cannot turn square boards.

Vasya is required to construct a fence of length l, however, an arbitrary fence won't do. Vasya wants his fence to look beautiful. We'll say that a fence is beautiful if and only if the following two conditions are fulfilled:

  • there are no two successive boards of the same type
  • the first board of the fence has an arbitrary length, and the length of each subsequent board equals the width of the previous one

In other words, the fence is considered beautiful, if the type of the i-th board in the fence is different from the i - 1-th board's type; besides, the i-th board's length is equal to the i - 1-th board's width (for all i, starting from 2).

Now Vasya wonders, how many variants of arranging a fence for his land exist. Your task is to count the number of different beautiful fences of length l.

Two fences will be considered the same if the corresponding sequences of fence boards types and rotations are the same, otherwise the fences are different. Since the sought number can be large enough, you need to calculate the answer modulo 1000000007 (109 + 7).

Input

The first line contains two integers n and l (1 ≤ n ≤ 100, 1 ≤ l ≤ 3000) — the number of different board types and the fence length, correspondingly. Next n lines contain descriptions of board types: the i-th line contains two integers ai and bi(1 ≤ ai, bi ≤ 100) — the sizes of the board of the i-th type. All numbers on the lines are separated by spaces.

Output

Print a single integer — the sought number of variants modulo 1000000007 (109 + 7).

Example
Input
2 3
1 2
2 3
Output
2
Input
1 2
2 2
Output
1
Input
6 6
2 1
3 2
2 5
3 3
5 1
2 1
Output
20
Note

In the first sample there are exactly two variants of arranging a beautiful fence of length 3:

  • As the first fence board use the board of the first type of length 1 and width 2. As the second board use board of the second type of length 2 and width 3.
  • Use one board of the second type after you turn it. That makes its length equal 3, and width — 2.

 【题解】 

 大致题意:有一块地要围上篱笆,现在有m种篱笆,要求用这些篱笆围成长度为 l 的围墙,相邻两个篱笆不能是同一种,并且后一块篱笆的长度应为前一块篱笆的宽度,求最后能围成长为 l 的方案数。

 

 分析:

 很显然用动规做,但是怎么写递推式呢?

 我们不妨分析一下,题中有两种状态,即取这块篱笆,和不取这块篱笆,似乎可以用状压做,但是再分析,一块篱笆还可以长宽互换,但是类型还是同一种类型,这一点在状压中就没办法表示,所以要放弃状压,那怎么办呢?题目说了,最后要求围成长度为 l 时的方案数,那长度为l 的方案数是不是就是长度为 l-1 时的方案数加上当前方案数,所以,

 我们就可以用dp[i][j]表示当前长度为 i 时而最后一块篱笆为 j 类型时的方案数。

具体看代码注释。

 【AC代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int inf=1e9+7;
typedef long long ll;
const int N=230;
const int M=3500;
int m,n;
int a[N],b[N];
ll dp[M][N];//表示长度为M且为第N种篱笆时的方案数

int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        memset(dp,0,sizeof(dp));
        for(int i=0;i<m;++i)
        {
            scanf("%d%d",&a[i],&b[i]);
            dp[a[i]][i]++;  //类型为i长度为a[i]时的方案数加1
            if(a[i]!=b[i])//如果不是正方形
            {
                a[i+m]=b[i];//长宽颠倒  
                b[i+m]=a[i];
                dp[a[i+m]][i+m]++;//长宽互换后成为新的类型,方案数加1
            }
        }
        for(int i=1;i<=n;++i)//遍历长度为i时的方案数
        {
            for(int j=0;j<m*2;++j)//遍历最后一个为j类型时的方案数
            {
                if(!dp[i][j]) continue;//不存在此种类型的篱笆
                for(int k=0;k<2*m;++k)//寻找下一块长度等于当前宽度的篱笆
                {
                    if(j%m!=k%m && a[k]==b[j])//前面是判断不为同一种类型  后面是判断下一块的长度等于上一块的宽度
                        dp[i+a[k]][k]=(dp[i+a[k]][k]+dp[i][j])%inf;//方案数累加
                }
            }
        }
        ll ans=0;
        for(int i=0;i<2*m;++i)//统计长度为n最后一个类型为i时的方案数
            ans=(ans+dp[n][i])%inf;
        printf("%lld\n",ans);
    }
    return 0;
}



区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值