暑假考试题8:mine(dp)

题目:

 分析:

这个数据范围只能做线性递推或加一个log。而这道题要求方案数,很容易联想到dp。主要是dp的转移情况多且复杂。

特别要考虑1,因为可能是1的前面或后面有*,于是就将1的情况一分为二:前面的1和后面的1(指的是*1的前面还是后面)

考虑每一位能够由前一位的哪些状态转移过来:

0:   前1和0

前1:  *

后1:   0 和 前1

* :   后1 和 2 和 *

2: *

:前面转移的都可以转移一遍,因为这一位可以填很多种

然后设dp[ i ] [ 0/1/2/3 ] [ 0/1 ]为递推到第i位,这一位填0或1或*或2 的方案数,最后一维0表示前1,1表示后1。

注意初始化和输出。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1000005
const ll mod=1e9+7;
ll dp[N][5][3];
char s[N];
int main()
{
    freopen("mine.in","r",stdin);
    freopen("mine.out","w",stdout);
    scanf("%s",s+1);
    int len=strlen(s+1);
    if(s[1]=='?') dp[1][0][0]=1,dp[1][2][0]=1,dp[1][1][1]=1;
    else if(s[1]=='0') dp[1][0][0]=1;
    else if(s[1]=='*') dp[1][2][0]=1;
    else if(s[1]=='1') dp[1][1][1]=1;
    //2->*
    for(int i=2;i<=len;i++)
    if(s[i]=='0'){
        dp[i][0][0]=(dp[i-1][0][0]+dp[i-1][1][0])%mod;
    }
    else if(s[i]=='1'){
        dp[i][1][0]=dp[i-1][2][0];
        dp[i][1][1]=(dp[i-1][0][0]+dp[i-1][1][0])%mod;//
    }
    else if(s[i]=='2'){
        dp[i][3][0]=dp[i-1][2][0];
    }
    else if(s[i]=='*'){
        dp[i][2][0]=(dp[i-1][2][0]+dp[i-1][1][1]+dp[i-1][3][0])%mod;//
    }
    else if(s[i]=='?'){
        dp[i][0][0]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;
        dp[i][1][0]=dp[i-1][2][0]; dp[i][1][1]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;//
        dp[i][2][0]=(dp[i-1][2][0]+dp[i-1][1][1]+dp[i-1][3][0])%mod;//+dp[i-1][3][0]
        dp[i][3][0]=dp[i-1][2][0];
    }
    if(s[len]=='?')
     printf("%lld\n",(dp[len][0][0]+dp[len][1][0]+dp[len][2][0])%mod);
    else if(s[len]=='0')
     printf("%lld\n",dp[len][0][0]);
    else if(s[len]=='1')
     printf("%lld\n",dp[len][1][0]);
    else if(s[len]=='*')
     printf("%lld\n",dp[len][2][0]);
    else printf("0\n");
    return 0;
}
/*
?1?
1??1
*2*??
???
??
0?*?*100???*2??0???
0?*?*100???*2*?0???
*/

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11436660.html