题解Luogu P5342 [TJOI2019]甲苯先生的线段树

Posted yzhang-rp-inf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Luogu P5342 [TJOI2019]甲苯先生的线段树相关的知识,希望对你有一定的参考价值。

原题传送门

挺有趣的一道题

\(c=1\),暴力求出点权和n即可

\(c=2\),先像\(c=1\)一样暴力求出点权和n,考虑有多少路径点权和也为n

考虑设x为路径的转折点,\(L\)\(x\)向左儿子走的长度,\(R\)\(x\)向右儿子走的长度。易知当\(L,R\)确定时,有唯一的\(x\)对应

\(x\)为转折点,\(L,R\)为向左/右儿子走的距离,这时点权和至少为\(Min=(2^{L+1}+2^{R+1}-3)x+2^R-1\)

此时x的取值一定珂以求出。考虑一下如何产生剩下\(n-Min\)的贡献,这个贡献一定是原来向左儿子走改成向右儿子走所带来的

我们珂以进行记忆化搜索求出答案,记录\(f[i][j][k]\)表示为向左/右儿子走的距离为\(i,j\)还差贡献为\(k\)的方案数(注意:答案要减去原来已有的那个解)

#include <bits/stdc++.h>
#define ll long long 
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read()
{
    register ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register ll x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline int Max(register int x,register int y)
{
    return x>y?x:y;
}
inline int dep(register ll n)
{
    int res=0;
    while(n)
        ++res,n>>=1;
    return res;
}
map<ll,ll> mp[55][55];
inline ll dfs(register int x,register int y,register ll z)
{
    if(x<y)
        x^=y^=x^=y;
    if(z<0||z>(2ll<<x)+(2ll<<y)-x-y-4)
        return 0;
    if(!x&&!y)
        return !z;
    if(mp[x][y].count(z))
        return mp[x][y][z];
    return mp[x][y][z]=dfs(x-1,y,z)+dfs(x-1,y,z-(1ll<<x)+1);
}
int T,d,c;
ll a,b,n,ans;
int main()
{
    T=read();
    while(T--)
    {
        n=0;
        d=read(),a=read(),b=read(),c=read();
        while(a!=b)
        {
            if(a>b)
                n+=a,a>>=1;
            else
                n+=b,b>>=1;
        }
        n+=a;
        if(c==1)
        {
            write(n),puts("");
            continue;
        }
        ans=0;
        if(dep(n)<=d)
            ++ans;
        for(register int l=1;l<=d;++l)
        {
            ll k=(2ll<<l)-1;
            if(k<=n&&dep(n/k)+l<=d)
                ans+=dfs(l,0,n%k);
        }
        for(register int l=1;l<=d;++l)
            for(register int r=1;r<=d;++r)
            {
                ll k=(2ll<<l)+(2ll<<r)-3,b=(1ll<<r)-1;
                if(k+b<=n&&dep((n-b)/k)+Max(l,r)<=d)
                    ans+=dfs(l-1,r-1,(n-b)%k);
            }
        write(ans-1),puts("");
    }
    return 0;
}

以上是关于题解Luogu P5342 [TJOI2019]甲苯先生的线段树的主要内容,如果未能解决你的问题,请参考以下文章

题解Luogu P5339 [TJOI2019]唱跳rap和篮球

题解Luogu P5340 [TJOI2019]大中锋的游乐场

题解 luogu 3857 [TJOI2008]彩灯 (线性基)

luogu题解 P3763 [TJOI2017]DNA

luogu P3879 [TJOI2010]阅读理解 题解

题解Luogu P4588 [TJOI2018]数学计算