您的位置:首页 > 其它

cf上一道超狠的dp

2014-03-20 20:19 197 查看
[align=center]D. Minesweeper 1D[/align]
[align=center]time limit per test[/align]
[align=center]2 seconds[/align]
[align=center]memory limit per test[/align]
[align=center]512 megabytes[/align]
[align=center]input[/align]
[align=center]standard input[/align]
[align=center]output[/align]
[align=center]standard output[/align]
Game "Minesweeper 1D" is played on a line of squares, the line's height is 1 square, the line's width is
n squares. Some of the squares contain bombs. If a square doesn't contain a bomb, then it contains a number from 0 to 2 — the total number of bombs in adjacent squares.

For example, the correct field to play looks like that:
001*2***101*. The cells that are marked with "*" contain bombs. Note that on the correct field the numbers represent the number of bombs in adjacent cells. For example, field
2* is not correct, because cell with value 2 must have two adjacent cells with bombs.

Valera wants to make a correct field to play "Minesweeper 1D". He has already painted a squared field with width of
n cells, put several bombs on the field and wrote numbers into some cells. Now he wonders how many ways to fill the remaining cells with bombs and numbers are there if we should get a correct field in the end.

Input
The first line contains sequence of characters without spaces
s1s2...
sn
(1 ≤ n ≤ 106), containing only characters "*", "?" and digits "0", "1"
or "2". If character
si equals "*", then the
i-th cell of the field contains a bomb. If character
si equals "?", then Valera hasn't yet decided what to put in the
i-th cell. Character
si, that is equal to a digit, represents the digit written in the
i-th square.

Output
Print a single integer — the number of ways Valera can fill the empty cells and get a correct field.

As the answer can be rather large, print it modulo 1000000007
(109 + 7).

Sample test(s)

Input
?01???


Output
4


Input
?


Output
2


Input
**12


Output
0


Input
1


Output
0


Note
In the first test sample you can get the following correct fields:
001**1, 001***,
001*2*, 001*10.

这题的难度我已无话可说……
先贴代码,再分析:
#include<iostream>
#include<cstring>
#include<utility>
#include<vector>
#include<algorithm>
#include <functional>
#include<list>
#include<iterator>
#include<deque>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#define Maxn 1000010#define mod 1000000007
using namespace std;
class string_cmp
{
public:
bool operator()(const char *str1,const char *str2) const
{
return strcmp(str1,str2)<0;
}
};
int dp[Maxn][3];
char str[Maxn];
int main()
{
cin>>str;
int len=strlen(str);
if(str[0]=='0'||str[0]=='?') dp[1][0]=1;
if(str[0]=='*'||str[0]=='?') dp[1][1]=1;
if(str[0]=='1'||str[0]=='?') dp[1][2]=1;
for(int i=2;i<=len;i++){
if(str[i-1]=='0'||str[i-1]=='?') dp[i][0]=dp[i-1][0];
if(str[i-1]=='1'||str[i-1]=='?'){
dp[i][2]=dp[i-1][0];
dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;
}
if(str[i-1]=='2'||str[i-1]=='?')
dp[i][2]=(dp[i][2]+dp[i-1][1])%mod;
if(str[i-1]=='*'||str[i-1]=='?')
dp[i][1]=(dp[i-1][1]+dp[i-1][2])%mod;
}
cout<<(dp[len][0]+dp[len][1])%mod<<endl;
return 0;
}

首先说一下:dp数组的含义,dp[i][j]表示前i的字符的j状态,j=0表示平衡态,有两种……0和……*1;j=1,表示多*态,有……*一种;j=2,表示缺*态,有……*2和……1(1前无*),……表示正确的任意组合,这对后面的决策已经没有影响了,故不考虑。
然后开始分析:
当遇到下一个字符,比如'0',那么根据游戏规则,0前不能是多*态和缺*态,因此可以肯定只能是平衡态,并且两种平衡态都符合要求,加上'0'后变成平衡态,故转移式dp[i][0]=dp[i-1][0];
再如'1',那么根据游戏规则,1前可以是平衡态或者多*态,并且多*态加上1后均变成了平衡态,故转移式dp[i][0]=dp[i-1][1],平衡态加上1后变成缺*态,故转移式dp[i][2]=dp[i-1][0];;
再如'2’,那么根据游戏规则,2前只能是多*态,并且加上2后,变成缺*态,故转移式dp[i][2]=dp[i-1][1];
再如'*',那么根据游戏规则,*前可以是多*态或者缺*态,加上*后均变成多*态,注意:缺*态+*不等于平衡态,因为这个*既可以与前面结合,又可以与后面结合,你要是在这里犯错误,那前面的都全白推了,所有的努力白费了,你还检查不出程序的错误,就悲剧了,故转移式dp[i][1]=(dp[i-1][1]+dp[i-1][2])%mod;
再如'?',那就相当复杂了,它可以替代任何字符,因此上面所有的转移式它都可以有;
但是,你会发现上面的程序和这有点不一样,那是因为已经合并过很多式子了,如果觉得看得有压力,那就直白翻译,分'?'和非'?'两种情况,再逐个击破,相信也能AC。
注意:初值要小心,这步再错,更加悲剧:第一个不可能是2,因此2的后,初始全0,这种三个都为0,转移下去必然为0,这样不可能状态就得到了,其余情况:如0,是平衡态,因此dp[1][0]=1;如1:,是缺*态,因此dp[1][2]=1;如*,是多*态,因此dp[1][1]=1;这三个都是合法状态,因此必然有一个dp不为0的,也能为转移到一下一个状态做好准备。如'?',那么上面都必须赋值为1,因为'?'可以替代任何字符。
最后的结果,当然是0或者*1结尾的平衡态,或者*结尾的多*态,01或者*2这样无法结尾,因此没有缺*态,所以输出<<(dp[len][0]+dp[len][1])%mod;
再者,记住只有'?'号才能发生相加情况,其余全是赋值,因为其余都是确定的方案,而'?'号可以多重选择,根据排列组合分类原理,是加法原理……合并时要小心,要全局看整个程序,特别是'?'执行完的下一句,统一转移时,可以统一的原因在于
初值为0,前面非'?'的,下一步相加,就等价于+0,其实就是赋值,'?'的前面已覆盖值,下一步相加,就等价于两类情况相加。
这个必须发上一贴,不然明天我连自己怎么想的都忘了,研究了这么长时间,再忘记,岂不是亏大了!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: