【JZOJ1421】二叉树

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种路线。
  一组行走路线的价值等于所有匹配该模式的路线的价值之和。请你编程计算给定路线的价值。


analysis

  • 递推DP?

  • f [ i ] f[i] f[i]为到第 i i i层的贡献和,注意这里 P P P视为自己下一层仍连向自己

  • 那么可以知道 L : f [ i ] = f [ i − 1 ] ∗ 2 , R : f [ i ] = f [ i − 1 ] ∗ 2 + 1 , P : f [ i ] = f [ i − 1 ] L:f[i]=f[i-1]*2,R:f[i]=f[i-1]*2+1,P:f[i]=f[i-1] L:f[i]=f[i1]2,R:f[i]=f[i1]2+1,P:f[i]=f[i1]

  • 但是对于填任意字母,会连出三个儿子,贡献为 f [ i − 1 ] ∗ 5 + 1 f[i-1]*5+1 f[i1]5+1

  • 注意分叉会对 R R R和任意字母有更多的贡献,所以把上面的 + 1 +1 +1全部改成 + 分 叉 数 量 +分叉数量 +

  • 比赛时高精度没压位 T T T了……


code

#include
#include
#include
#define MAXN 10005
#define mod 1000000000
#define ll long long
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)

using namespace std;

char st[MAXN];
ll n;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
struct BIGNUM
{
	ll num[MAXN/10],len;
	BIGNUM()
	{
		memset(num,0,sizeof(num)),len=1;
	}
	BIGNUM operator=(const ll x)
	{
		ll temp=x;
		len=1;
		do
		{
			num[len-1]=temp%mod;
			temp/=mod,len++;
		}while (temp);
		while (num[len-1]==0 && len>1)--len;
		return *this;
	}
	BIGNUM operator+(const BIGNUM &x)const
	{
		BIGNUM temp;
		temp.len=max(len,x.len)+1;
		fo(i,0,temp.len-1)
		{
			temp.num[i]+=num[i]+x.num[i];
			temp.num[i+1]=temp.num[i]/mod;
			temp.num[i]%=mod;
		}
		while (temp.num[temp.len-1]==0 && temp.len>1)--temp.len;
		return temp;
	}
	BIGNUM operator*(const BIGNUM &x)const
	{
		BIGNUM temp;
		temp.len=len+x.len;
		fo(i,0,len-1)
		{
			fo(j,0,x.len-1)
			{
				temp.num[i+j]+=num[i]*x.num[j];
				temp.num[i+j+1]+=temp.num[i+j]/mod;
				temp.num[i+j]%=mod;
			}
		}
		while (temp.num[temp.len-1]==0 && temp.len>1)--temp.len;
		return temp;
	}
	void print()
	{
		fd(i,len-1,0)
		{
			if (i<len-1)
			{
				if (num[i]<100000000)printf("0");
				if (num[i]<10000000)printf("0");
				if (num[i]<1000000)printf("0");
				if (num[i]<100000)printf("0");
				if (num[i]<10000)printf("0");
				if (num[i]<1000)printf("0");
				if (num[i]<100)printf("0");
				if (num[i]<10)printf("0");
			}
			printf("%d",num[i]);
		}
		printf("\n");
	}
}f[2],g,three;
int main()
{
	//freopen("T1.in","r",stdin);
	scanf("%s",st+1),n=strlen(st+1);
	f[0]=g=1;three=3;
	fo(i,1,n)
	{
		ll now=i&1,last=now^1;
		BIGNUM two,five;two=2,five=5;
		if (st[i]=='P')f[now]=f[last];
		else if (st[i]=='L')f[now]=f[last]*two;
		else if (st[i]=='R')f[now]=f[last]*two+g;
		else f[now]=f[last]*five+g,g=g*three;
	}
	f[n&1].print();
	return 0;
}

你可能感兴趣的:(模拟赛,DP)