Description(translated)
定义明确表达式
UAE
U
A
E
:
1. 自然数都是
UAE
U
A
E
(带前导零的也算)——换句话说,数字串是
UAE
U
A
E
2. 对于两个
UAE
U
A
E
:
X
X
与,
(X)+or−or∗or/(Y)
(
X
)
+
o
r
−
o
r
∗
o
r
/
(
Y
)
是
UAE
U
A
E
3. 对于一个
UAE
U
A
E
:
X
X
,与
−(X)
−
(
X
)
都是
UAE
U
A
E
给出一个
UAE
U
A
E
,它的括号都被删掉了,请求出可以满足这个条件的
UAE
U
A
E
的个数
Input
一行,一个字符串,仅包含 +、−、∗、/ + 、 − 、 ∗ 、 / 以及数字 0到9 0 到 9 ,不超过 2000 2000 个字符
Output
一行,一个整数,表示方案数
Sample Input
sample1.in
1+2*3
sample2.in
03+-30+40
sample3.in
5/0
Sample Output
sample1.out
2
sample2.out
3
sample3.out
1
Solution
好神的一道题……
第一,区间
DP
D
P
的
O(n3)
O
(
n
3
)
不说了,简单
然后,如果没有连续的符号,很显然每个符号都等价了
设符号有
a
a
个,那么,
f[1]=1
f
[
1
]
=
1
可以
O(n)
O
(
n
)
求出,当然数据范围小,
O(n2)
O
(
n
2
)
也没人打你
现在我们考虑有连续的符号该怎么办
先简单判一下无解
1. 如果
∗、/
∗
、
/
前面是运算符或者前面没有字符,无解
2. 如果末尾出现运算符,无解
然后就都是有解的了……
考虑一下删去括号之前的
UAE
U
A
E
,为其添加一些奇怪的东西——在正负号前面添加一组括号。举个栗子——
(+(233))−(8)
(
+
(
233
)
)
−
(
8
)
变成
(()+(233))−(8)
(
(
)
+
(
233
)
)
−
(
8
)
由于每个运算符前后都有括号,我们去掉后方括号,上式变成
(()+233)−8
(
(
)
+
233
)
−
8
,省略数字和运算符就变成了
(())
(
(
)
)
。
神奇的是,每个运算符号恰好对应一个右括号,运算的顺序和括号的运算顺序也是一样的,不难发现,每个满足条件的 UAE U A E 恰好对应一个合法括号序列,每个合法括号序列也恰好对应一个满足条件的 UAE U A E 。但是考虑一下作为正负号的 +、− + 、 − ,可以发现它的右括号前面是空的,也就是说必须左右括号紧挨着才可以,写一个组合数学 DP D P 不是什么难事。
做这道题的时候莫名想起了 prufer p r u f e r 数列,每一棵有标号无根树都可以转化为唯一的 prufer p r u f e r 数列,而每一个 prufer p r u f e r 数列都可以转化为唯一的有标号无根树,而树不容易计数,但 prufer p r u f e r 数列却很好计数,这样一转化就简单多了。
这题也是一样,把不好计数的 UAE U A E 转化为比较容易计数的括号序列,好神啊……
PS: P S : 我还是太弱了,看了题解还是WA了,忘了特判末尾有运算符的无解情况……
Code: C o d e :
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 4005
#define mod 1000003
char S[N];
int n,m,v[N],f[N][N];
int main()
{
scanf("%s",S+1);
n=strlen(S+1);
for(int i=1;i<=n;i++)
{
if(S[i]=='+'||S[i]=='-')
{
m++;
if(S[i-1]<'0'||S[i-1]>'9')
v[m]=1;
}
if(S[i]=='*'||S[i]=='/')
{
m++;
if(S[i-1]<'0'||S[i-1]>'9')
{
puts("0");
return 0;
}
}
}
if(S[n]<'0'||S[n]>'9')
{
puts("0");
return 0;
}
f[0][0]=1;
for(int i=0;i<=2*m;i++)
{
for(int j=0;j<=min(m,i);j++)
{
int k=i-j;
if(j<k)continue;
if(j<m)
f[i+1][j+1]=(f[i+1][j+1]+f[i][j])%mod;
if(j>0)
{
if(v[k+1])
f[i+1][j]=(f[i+1][j]+f[i-1][j-1])%mod;
else
f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
}
}
}
printf("%d\n",f[2*m][m]);
}