题目
Description
在一个无穷的满二叉树中,有以下几个特点:
(1) 每个节点都有两个儿子——左儿子和右儿子;
(2) 如果一个节点的编号为X,则它的左儿子编号为2X,右儿子为2X+1;
(3) 根节点编号为1。
现在从根结点开始走,每一步有三种选择:走到左儿子、走到右儿子和停在原地。
用字母“L”表示走到左儿子,“R”表示走到右儿子,“P”表示停在原地,用这三个字母组成的字符串表示一个明确的行走路线。
一个明确的行走路线的价值为最终到达节点的编号,例如LR的价值为5,而RPP的价值为3。
我们用字符“L”、“R”、“P”和“”组成的字符串表示一组行走路线,其中“”可以是“L”、“R”、“P”中的任意一种,所有跟这个行走路线匹配的字符串都认为是可行的。
例如L*R包含LLR、LRR和LPR。而**包含LL、LR、LP、RL、RR、RP、PL、PR和PP这9种路线。
一组行走路线的价值等于所有匹配该模式的路线的价值之和。请你编程计算给定路线的价值。
Input
输入一个字符串表示一组行走路线,里面只含有“L”、“R”、“P”和“*”四种字符,长度不会超过10000。
Output
输出该路线的价值。
Sample Input
输入1:
P*P
输入2:
L*R
输入3:
**
输入4:
LLLLLRRRRRLLLLLRRRRRLLLLLRRRRRLLLLL
Sample Output
输出1:
6
输出2:
25
输出3:
33
输出4:
35400942560
Hint
【数据范围】
30%的数据满足路线中不含“”;
50%的数据满足最多只有3个“”。
分析
对于前面50%的数据是非常简单的,
按照题目上面说的去做,加上一个高精度就没问题了。
如果要通过所以的数据,就要想一下其他办法。
题解
观察一下,几个符号分别有什么作用。
L:给目前的答案×2
R:给目前的答案×2,然后加上1。
P:给目前的答案×1,其实什么也没有干。
*:可以变成L,R,P,也就是对上面的求和。
如果全部是乘法,那么就是很简单的,可以用乘法分配律。
但是,现在还有加法。
我们对 * 操作来分析一下,
设 f i f_i fi 表示第i位的价值。
则可以得出以下结论:
L: f i f_i fi= f i − 1 f_{i-1} fi−1×2
R: f i f_i fi= f i − 1 f_{i-1} fi−1×2+1
P: f i f_i fi= f i − 1 f_{i-1} fi−1×1
*: f i f_i fi=操作L+操作R+操作P= f i − 1 f_{i-1} fi−1×5+1
- 但是,后面的加1如何处理?
如果我们遇到了1个 * 操作,那么一个串就变成了3个串;
如果我们遇到了2个 * 操作,那么一个串就变成了9个串;
如果我们遇到了3个 * 操作,那么一个串就变成了27个串;
……
如果我们遇到了N个 * 操作,那么一个串就变成了 3 N 3^N 3N个串。
所以,每一个加1操作就是加上 3 N 3^N 3N
所以, f [ ] f[] f[] 的递推式就变为:
L: f i f_i fi= f i − 1 f_{i-1} fi−1×2
R: f i f_i fi= f i − 1 f_{i-1} fi−1×2+ 3 N 3^N 3N
P: f i f_i fi= f i − 1 f_{i-1} fi−1×1
*: f i f_i fi= f i − 1 f_{i-1} fi−1×5+ 3 N 3^N 3N
这里的N表示从1到i中,操作 * 的个数。
- 注意高精度的时候可以压位。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <stdlib.h>
#include <math.h>
#define mo 10000
using namespace std;
typedef int arr [3000];
arr sum,num,ans,t;
char a[10003],ch;
int m,n;
void add(arr a,arr b)
{
memset(t,0,sizeof(t));
int m=max(a[0],b[0]);
for(int i=1;i<=m;i++)
{
t[i]+=a[i]+b[i];
t[i+1]+=t[i]/mo;
t[i]-=t[i+1]*mo;
}
if(t[m+1]>0)t[0]=m+1;else t[0]=m;
}
void ttt(arr a,int b)
{
memset(t,0,sizeof(t));
for(int i=1;i<=a[0];i++)
{
t[i]+=a[i]*b;
t[i+1]=t[i]/mo;
t[i]-=t[i+1]*mo;
}
if(t[a[0]+1]>0)t[0]=a[0]+1;else t[0]=a[0];
}
int main()
{
ch=getchar();
while((ch!='P')&&(ch!='L')&&(ch!='R')&&(ch!='*'))ch=getchar();
while((ch=='P')||(ch=='L')||(ch=='R')||(ch=='*'))
{
if(ch=='P')
{
ch=getchar();
continue;
}
n++;
a[n]=ch;
ch=getchar();
}
sum[1]=1;
sum[0]=1;
ans[1]=1;
ans[0]=1;
for(int k=1;k<=n;k++)
{
if(a[k]=='L')
{
ttt(ans,2);
memcpy(ans,t,sizeof(ans));
}
if(a[k]=='R')
{
ttt(ans,2);
memcpy(ans,t,sizeof(ans));
add(ans,sum);
memcpy(ans,t,sizeof(t));
}
if(a[k]=='*')
{
ttt(ans,5);
memcpy(ans,t,sizeof(ans));
add(ans,sum);
memcpy(ans,t,sizeof(t));
ttt(sum,3);
memcpy(sum,t,sizeof(sum));
}
}
printf("%d",ans[ans[0]]);
for(int i=ans[0]-1;i;i--)
{
if(ans[i]<1000)printf("0");
if(ans[i]<100)printf("0");
if(ans[i]<10)printf("0");
printf("%d",ans[i]);
}
}