您的位置:首页 > 其它

[NOIP模拟]Fantasy Strange Tree

2017-08-24 14:55 127 查看
题目描述:

FST 的脑洞非常大,经常幻想出一些奇怪的东西。

某一天,FST 幻想出了一棵没有边际的二叉树,脑补着在那棵二叉树上行走的场景。

FST 一开始在二叉树的根,然后 FST 写下了一个由 ‘L’‘R’ 两种种字符构成的串,他称这个串为初始串,按照这个串的顺序,碰到一个 ‘L’ 就移动到左儿子,碰到一个 ‘R’ 就移动到右儿子。FST 最后的位置就是他的起点。

然后 FST 又写下一个串,他称这个串为操作串,由 ‘U’‘L’‘R’ 三种字符构成,‘U’ 表示移动到当前点的父亲(特殊地,我们定义根节点的父亲为根自己), ‘L’ ‘R’ 同上。

但是 FST 觉得直接按照操作串一步一步走十分无聊,所以 FST 会跳过一些操作(心情不好的时候也可能跳过所有操作,或不跳过),现在 FST 想知道他会走到多少种可能的终点。

由于答案可能很大,所以只需输出答案 mod(10^9+7) 的值。

输入格式:

第一行一个由‘L’‘R’两种字符构成的串。

第二行一个由‘U’‘L’‘R’三种字符构成的串。

输出格式:

输出一行,为答案 mod(10^9+7)。

样例输入:

LL

RU

样例输出:

3

样例说明:

FST 可以操作的串为 ” ‘R’ ‘U’ ‘RU’。

但是串 ‘RU’ 的效果和串 ” 是一样的,所以只能走到 3 个节点,如下图:



(这棵二叉树的大小是无穷的,这里只画出一部分)

数据范围:



题目分析:

这道题还是有点难以想到正解,但是正解又不难理解。我们记录一个数组f,记录当前可以到达的不同终点的数量,下表表示此点状态。f[1]表示只走过左儿子的点的个数,f[2]表示只走过右儿子的点的个数,f[0]表示两个儿子都没走过的点的个数,f[3]表示两个儿子都走过的点的个数。对于一个读入的新操作,因为可跳操作,于是所有目前的终点都能执行这个操作,以这些终点为基础,又可以得到一批点,其中未走过的点就是新的可能终点。

于是有更新关系:

if(ch=='L')//读入一个操作
{
f[1]=(f[1]+f[0])%mod;//对于原来两个儿子都没走过的点,再往左走可以让这个点变成只走过左儿子的点,所以原来的数量累加上f[0]
f[3]=(f[3]+f[2])%mod;//对于原来只走过右儿子的点,再往左走可以让这个点两个儿子都走过的点,所以原来的数量累加上f[2]
f[0]=(f[0]+f[2])%mod;//对于原来只走过右儿子的点和原来两个儿子都没走过的点,再往左走得到一个新的两个儿子都没走过的点,所以现在的数量等于原来的f[0]+f[2]
f[2]=0;//此时便不存在只走过右儿子的点,因为向左走后它们都变成了f[3],数量也转移给了f[3],于是清0
}
if(ch=='R')//基本同上
{
f[2]=(f[2]+f[0])%mod;
f[3]=(f[3]+f[1])%mod;
f[0]=(f[0]+f[1])%mod;
f[1]=0;
}


注意这几个转移操作所代表的意义:前两步是状态的变化,数量也在转移,所以才会有一个清0操作,因为有一种状态会不再存在。而第三步是表示新产生了一些终点,这些终点显然都是f[0],而它们也是由原先某两种点的数量所决定的。

对于u操作其实只会抵消l,r操作,对于初始串它可能增加一些终点,而对于操作串并不会增加,因为在操作串上所跳回的点,都已经被记作了可能终点。

附代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<algorithm>
using namespace std;

const int mod=1e9+7;
long long ans,f[4];
char t[100010],ch;
int num;

int main()
{
//freopen("fstalways.in","r",stdin);
//freopen("fstalways.out","w",stdout);

for(ch=getchar();ch>='A'&&ch<='Z';ch=getchar()) t[++num]=ch;
f[0]=1;//经历初始串可以得到一个终点
for(ch=getchar();ch>='A'&&ch<='Z';ch=getchar())
{
if(ch=='U')//每多一个U都可以多往上跳一步
{
if(num)
{
ch=t[num--];//可跳回的那个点也将是一个可能的终点
if(ch=='L') f[1]++;
else f[2]++;
}
continue;
}
if(ch=='L')
{
f[1]=(f[1]+f[0])%mod;
f[3]=(f[3]+f[2])%mod;
f[0]=(f[0]+f[2])%mod;
f[2]=0;
continue;
}
if(ch=='R')
{
f[2]=(f[2]+f[0])%mod;
f[3]=(f[3]+f[1])%mod;
f[0]=(f[0]+f[1])%mod;
f[1]=0;
continue;
}
}
for(int i=0;i<=3;i++)
ans=(ans+f[i])%mod;
printf("%d",ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: