[编程题]小Q的歌单(动态规划)

链接:https://www.nowcoder.com/questionTerminal/f3ab6fe72af34b71a2fd1d83304cbbb3
来源:牛客网
问题描述:
小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。 

输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。

输出描述:

输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。
示例1

输入

5
2 3 3 3

输出

9
解决思路:

1. 用数组dp来存储结果,dp[i][j]表示用前j首歌表示长度为i的歌单的方法数,i=1…K,j=1,…,na+nb。na是第1种歌的数量,nb是第2种歌的数量 
2. lens[j]表示第j首歌的长度,如果i>=lens[j],那么由前j首歌组成长度为i的歌单的方法数可分为两部分,第一部分是dp[i][j-1],即由前j-1首歌组成长度
为i的歌单的方法数,第二部分是dp[i-lens[j]][j-1],即由j-1首歌组成长度为i-lens[j]的歌单的方法数,因为第j首歌已经占据了lens[j]的长度。 
3. 如果i<lens[j]i<lens[j],那么dp[i][j][i][j]等于dp[i][j1][i][j−1]。
代码:
#include <iostream>
#include <algorithm>
#include<string.h>
#include<map>
#include<iterator>
#include<math.h>
using namespace std;
const int mod =1000000007;
int k;
int a,x,b,y;
int dp[1010][210];
int len[210];
int main()
{
    cin>>k;
    cin>>a>>x>>b>>y;
    int length=x+y;
    memset(dp,0,sizeof(dp));
    memset(len,0,sizeof(len));
    dp[0][0]=1;
    for(int i=1;i<=x;i++)
        len[i]=a;
    for(int i=x+1;i<=length;i++)
        len[i]=b;
    for(int i=0;i<=k;i++)
        for(int j=1;j<=length;j++)
    {
        if(i>=len[j])
        {
            dp[i][j]=(dp[i][j-1]+dp[i-len[j]][j-1])%mod;
        }
        else
        {
            dp[i][j]=dp[i][j-1]%mod;
        }
    }
    cout<<dp[k][length]<<endl;
    return 0;
}

 



posted @ 2018-08-08 21:17  左岸繁华右岸殇  阅读(1228)  评论(0编辑  收藏  举报