Concerts Gym - 101669A DP

题目链接

题目大意:

用A-Z表示音乐会,第一行给出一个k(1e3)和n(1e4),然后给出26个整数表示A-Z的音乐会听完之后要休息的天数,此期间不能去听音乐会,再然后给出一个长度为k的序列,表示John 计划听的音乐会,可以不连续,注意有时间间隔,可能有重复的要听的音乐会(eg:AAA),最后给出一个长度为n的序列,表示John得到的演出会的时间表,每天一场音乐会,求John按他的顺序听够k天音乐会,有多少种可能,结果mod  1e9+7;

题目思路:

长度为k的串为t串,长度为n的串为s串,s和t都从第0位开始,

用a数组保存听完第A-Z场音乐会需要休息多少天,a[0]代表第A场的休息天数

dp[1e3][1e4],dp[i][j]表示按顺序听够t串的i场音乐会,到s串的第j位,有多少种可能;dp[i][j]都从1开始;

听完第A场音乐会,只要间隔a[0]天及以上的天数以后的音乐会都可以听,所以每次dp[i][j]都要继承dp[i][j-1];

遍历一遍s串,如果s[i] = t[j],那么dp[j][i]=(dp[j][i-1]+dp[j-1][i-a[t[j-2]-'A']-1])%mod;

如果末尾能匹配上,也要继承前j-1场能匹配上的数量;

如果s[i] != t[j],那么dp[j][i]=dp[j][i-1];

ac代码:

#include 
using namespace std;
typedef long long ll;

ll n,k;
const int maxn=1e4+10;
const int mod=1e9+7;
ll dp[1010][maxn];//结果
ll a[30];//休息天数

int main()
{
    scanf("%lld%lld",&k,&n);
    for(int i=0;i<26;i++) scanf("%lld",&a[i]);
    string s,t;
    cin>>t>>s; 
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=s.size();i++){
        for(int j=1;j<=k;j++){
            if(t[j-1]==s[i-1]){
                if(j==1) dp[j][i]=(dp[j][i-1]+1)%mod;
//第1场不需要考虑前面的场了,直接继承前一位的结果并加一
                else if(i-a[t[j-2]-'A']-1>0) dp[j][i]=(dp[j][i-1]+dp[j-1][i-a[t[j-2]-'A']-1])%mod;
            }
            else dp[j][i]=dp[j][i-1];
        }
    }
    printf("%lld\n",dp[k][n]);//直接输出结果
    return 0;
}

 

你可能感兴趣的:(Concerts Gym - 101669A DP)