- 题意:
数字表示它两边的星号的个数,问号是不定。给定一个串,问满足题意的有几种可能 - 分析:
1.线性问题
2.可以从一个方向递推求得结果
- 方法1:
动态规划。dp[i][j][k],i代表1-i的都确定的一个状态,j代表当前状态的最后一个是否为*,k代表当前状态最后一位的下一位是否需要是* - 方法2:
记忆化搜索。由未知的问题集合开始推倒,逐步缩小未知集合的范围,知道最后得到解 - 关键:
分析清楚对于一个从起点开始长度一定的序列,它如果要求下一个长度的序列,那么状态如何转移。也就是说,如何去确定下一个应该是数字还是星号。
对于这个问题,必须是星号的前提就是前一个序列需要一个星号来补齐,那么这个是要保存的。然后继续分析,如果上一段需要当前未知是星号,那么是即可;如果不需要当前是星号,那么如果当前位是星号那无所谓,如果当前是数字,那么就要考虑:之前的一位是星号还是数字,这个对之后的转移是有影响的。所以,一共需要保存两个信息即可。
方法1:
const int MAXN = 1100000;
int dp[MAXN][2][2];
char ipt[MAXN];
int len;
void fun()
{
dp[0][0][0] = dp[0][0][1] = 1;
FE(i, 1, len)
{
if (ipt[i] == '?')
{
//0
dp[i][0][0] += dp[i - 1][0][0];
dp[i][0][0] %= MOD;
//1
dp[i][0][1] += dp[i - 1][0][0];
dp[i][0][1] %= MOD;
dp[i][0][0] += dp[i - 1][1][0];
dp[i][0][0] %= MOD;
//2
dp[i][0][1] += dp[i - 1][1][0];
dp[i][0][1] %= MOD;
//*
dp[i][1][0] += dp[i - 1][0][1];
dp[i][1][0] %= MOD;
dp[i][1][1] += dp[i - 1][0][1];
dp[i][1][1] %= MOD;
dp[i][1][0] += dp[i - 1][1][1];
dp[i][1][0] %= MOD;
dp[i][1][1] += dp[i - 1][1][1];
dp[i][1][1] %= MOD;
}
else
{
switch (ipt[i])
{
case '0':
dp[i][0][0] += dp[i - 1][0][0];
dp[i][0][0] %= MOD;
break;
case '1':
dp[i][0][0] += dp[i - 1][1][0];
dp[i][0][0] %= MOD;
dp[i][0][1] += dp[i - 1][0][0];
dp[i][0][1] %= MOD;
break;
case '2':
dp[i][0][1] += dp[i - 1][1][0];
dp[i][0][1] %= MOD;
break;
case '*':
dp[i][1][0] += dp[i - 1][0][1];
dp[i][1][0] %= MOD;
dp[i][1][0] += dp[i - 1][1][1];
dp[i][1][0] %= MOD;
dp[i][1][1] += dp[i - 1][0][1];
dp[i][1][1] %= MOD;
dp[i][1][1] += dp[i - 1][1][1];
dp[i][1][1] %= MOD;
break;
}
}
}
}
int main()
{
// freopen("in.txt", "r", stdin);
while (~RS(ipt + 1))
{
CLR(dp, 0);
len = strlen(ipt + 1);
fun();
cout << (dp[len][0][0] + dp[len][1][0]) % MOD << endl;
}
return 0;
}
- 对于这个方法,不断的缩小未知集合,不要忘了使用记忆化
方法2:
const int MAXN = 1100000;
int ans[MAXN][2][2];
char ipt[MAXN];
int len;
int fun(int ind, bool isPreStar, bool isCurStar)
{
if (ans[ind][isPreStar][isCurStar] != INF)
return ans[ind][isPreStar][isCurStar];
int ret = 0;
if (ind >= len)
{
if (!isCurStar)
ret = 1;
return ans[ind][isPreStar][isCurStar] = ret;
}
if (ipt[ind] == '?')
{
if (isPreStar)
{
if (isCurStar)
{
ret += fun(ind + 1, true, false);
ret %= MOD;
ret += fun(ind + 1, true, true);
ret %= MOD;
}
else
{
ret += fun(ind + 1, false, false);
ret %= MOD;
ret += fun(ind + 1, false, true);
ret %= MOD;
}
}
else
{
if (isCurStar)
{
ret += fun(ind + 1, true, true);
ret %= MOD;
ret += fun(ind + 1, true, false);
ret %= MOD;
}
else
{
ret += fun(ind + 1, false, false);
ret %= MOD;
ret += fun(ind + 1, false, true);
ret %= MOD;
}
}
}
else
{
if (isPreStar)
{
if (isCurStar)
{
if (ipt[ind] == '*')
{
ret += fun(ind + 1, true, false);
ret %= MOD;
ret += fun(ind + 1, true, true);
ret %= MOD;
}
}
else
{
switch (ipt[ind])
{
case '1':
ret += fun(ind + 1, false, false);
ret %= MOD;
break;
case '2':
ret += fun(ind + 1, false, true);
ret %= MOD;
break;
}
}
}
else
{
if (isCurStar)
{
if (ipt[ind] == '*')
{
ret += fun(ind + 1, true, true);
ret %= MOD;
ret += fun(ind + 1, true, false);
ret %= MOD;
}
}
else
{
switch (ipt[ind])
{
case '0':
ret += fun(ind + 1, false, false);
ret %= MOD;
break;
case '1':
ret += fun(ind + 1, false, true);
ret %= MOD;
break;
}
}
}
}
return ans[ind][isPreStar][isCurStar] = ret;
}
int main()
{
// freopen("in.txt", "r", stdin);
while (~RS(ipt))
{
CLR(ans, INF);
len = strlen(ipt);
int ans = 0;
ans += fun(0, false, false);
ans %= MOD;
ans += fun(0, false, true);
ans %= MOD;
cout << ans << endl;
}
return 0;
}