Gym 100507G The Debut Album (滚动数组dp)

The Debut Album

题目链接:

http://acm.hust.edu.cn/vjudge/contest/126546#problem/G

Description

Pop-group “Pink elephant” entered on recording their debut album. In fact they have only two songs: “My love” and “I miss you”, but each of them has a large number of remixes. The producer of the group said that the album should consist of 𝑛 remixes. On second thoughts the musicians decided that the album will be of interest only if there are no more than 𝑎 remixes on “My love” in a row and no more than 𝑏 remixes on “I miss you” in a row. Otherwise, there is a risk that even the most devoted fans won’t listen to the disk up to the end. How many different variants to record the album of interest from 𝑛 remixes exist? A variant is a sequence of integers 1 and 2, where ones denote remixes on “My love” and twos denote remixes on “I miss you”. Two variants are considered different if for some 𝑖 in one variant at 𝑖-th place stands one and in another variant at the same place stands two.

Input

The only line contains integers 𝑛, 𝑎, 𝑏 (1 ≤ 𝑎, 𝑏 ≤ 300; max(𝑎, 𝑏) + 1 ≤ 𝑛 ≤ 50 000).

Output

Output the number of different record variants modulo 109 + 7.

Examples

3 2 1 4

Explanation

In the example there are the following record variants: 112, 121, 211, 212.
##题意: 英语弱鸡表示题意真难看懂. 在n个位置填充1 or 2. 要求连续的1的个数不超过a,连续的2的个数不超过b. 求方案数.
##题解: 要考虑每一位可能放1或2,容易想到动态规划: dp[i][1/2][j]:到第i个位置时,放1且有连续j个1的方案(放2且有连续j个2的方案). 转移方程: j==1: dp[i][1][1] = Σdp[i-1][2][k] ,(k<=b), 即只放一个1的情况等同于前面有任意个连续2的情况. dp[i][2][1] = Σdp[i-1][1][k] ,(k<=a), 即只放一个2的情况等同于前面有任意个连续1的情况. j!=1: dp[i][1/2][j] = dp[i-1][1/2][j-1];
上述思路确定后,考虑数组内存的问题,由于n比较大,直接开三维数组估计会MLE. 由于转移具有线性型(i只能由i-1来). 所以可以用滚动数组压缩到二维数组. 注意考虑压缩后的各种问题: 如果后面需要的值在前面被改变了,那么就先需要记录下来. 对j进行枚举时,由于j用到j-1的值,所以要从大往小枚举.
一个简单的滚动数组dp写了一个小时,一直在瞎处理边界. 归根结底还是太弱了,dp还需多加练习.

##代码: ``` cpp #include #include #include #include #include #include #include #include #include #define LL long long #define eps 1e-8 #define maxn 550 #define mod 1000000007 #define inf 0x3f3f3f3f #define IN freopen("in.txt","r",stdin); using namespace std;

int n, a, b;
int dp[2][350];

int main(int argc, char const *argv[])
{
//IN;

while(scanf("%d %d %d", &n,&a,&b) != EOF)
{
    memset(dp, 0, sizeof(dp));

    dp[0][1] = dp[1][1] = 1;
    for(int i=2; i<=n; i++) {
        /*由于要滚动处理,先记录下会改变的值*/
        int tmpa = dp[0][1];
        int tmpb = dp[1][1];
        dp[0][1] = 0;
        for(int j=1; j<=b; j++)
            dp[0][1] = (dp[0][1] + dp[1][j]) % mod;
        dp[1][1] = tmpa;
        for(int j=2; j<=a; j++)
            dp[1][1] = (dp[1][1] + dp[0][j]) % mod;

        /*由于要滚动处理,需要从后往前覆盖*/
        for(int j=a; j>=3; j--) {
            dp[0][j] = dp[0][j-1];
        }
        if(a >= 2) dp[0][2] = tmpa;

        for(int j=b; j>=3; j--) {
            dp[1][j] = dp[1][j-1];
        }
        if(b >= 2) dp[1][2] = tmpb;
    }

    int ans = 0;
    for(int i=1; i<=a; i++)
        ans = (ans + dp[0][i]) % mod;
    for(int i=1; i<=b; i++)
        ans = (ans + dp[1][i]) % mod;

    printf("%d\n", ans);
}

return 0;

}

posted @ 2016-08-07 17:00  Sunshine_tcf  阅读(390)  评论(0编辑  收藏  举报