【题解】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;
}

原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10933615.html

时间: 2024-10-31 07:45:30

【题解】Luogu P5342 [TJOI2019]甲苯先生的线段树的相关文章

luogu P5338 [TJOI2019]甲苯先生的滚榜

传送门 首先,排名系统,一看就知道是原题,可以上平衡树来维护 然后考虑一种比较朴素的想法,因为我们要知道排名在一个人前面的人数,也就是AC数比他多的人数+AC数一样并且罚时少的人数,所以考虑维护那两个东西.AC数更多的人数显然可以直接上树状数组.后者的话可以对每一种AC数开值域线段树,存每个罚时有多少人,注意到罚时之和不会超过\(1.5*10^6\),所以动态开点线段树可以轻松解决.然后每次有个人AC数和罚时改变就先在原来的位置-1,然后在新位置+1.每次询问就是树状数组上AC数\(>\)当前A

Solution: 题解 CF896C Willem, Chtholly and Seniorious(线段树解珂朵莉树)

Intro: 珂朵莉树模板题 怎么所有题解都是珂朵莉树啊啊啊啊 于是本蒟蒻决定来一发中(feng)规(kuang)中(luan)矩(gao)的线段树 首先这棵线段树只维护懒标记 来一发定义 线段树节点\(u\)维护区间\([l_u,r_u]\)的内容 懒标记\(t_u\):当\(t_u\not=0\)时表示区间\([l_u,r_u]\)全是\(t_u\),\(t_u=0\)就是没有懒标记 建立线段树 在建立时顺便处理\(l_u,r_u\),只要当\(l_u=r_u\)时就打上标记 P.s \(L

[luogu P3801] 红色的幻想乡 [线段树][树状数组]

题目背景 蕾米莉亚的红雾异变失败后,很不甘心. 题目描述 经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放. 我们将幻想乡看做是一个n*m的方格地区,一开始没有任何一个地区被红雾遮盖.蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区.如果两阵红雾碰撞,则会因为密度过大而沉降消失.灵梦察觉到了这次异变,决定去解决它.但在解决之前,灵梦想要了解一片范围红雾的密度.可以简述为两种操

【题解】CODEVS 1217 借教室 zkw线段树(区间最值)

捣鼓了好长时间才终于把zkw线段树的区间最值修改给A掉了 = =zkw神犇的课件里竟然有错! (╯▽╰)下面的伪代码里被注释的是我修改的>< Func Add_x(s,t,x) for (s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) T[s^1]+=x; if ( t&1) T[t^1]+=x; A=min(T[s],T[s^1]),T[s]-=A,T[s^1]-=A, T[s>>1]+=A;

[luogu P3797] 妖梦斩木棒 [线段树]

题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’X’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’.幽幽子吃饱后闲来无事,决定戏弄一下妖梦.她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题.这些操作可以这样描述: 1 x C 将第x个小段的木棒替换成C型

【题解】Berland.Taxi Codeforces 883L 模拟 线段树 堆

Prelude 题目传送门:ヾ(?ω?`)o Solution 按照题意模拟即可. 维护一个优先队列,里面装的是正在运营中的出租车,关键字是乘客的下车时间. 维护一个线段树,第\(i\)个位置表示第\(i\)个房子前面有没有停放出租车,这样在有人需要打车的时候可以快速找到离她最近的车的位置. 对每个房子维护一个堆,里面装的是停在这个房子前面的出租车,关键字是出租车的编号和上一个乘客下车的时间,上一个乘客下车越早,等待时间越长. 然后模拟时间的流逝就可以了,代码非常好写. Code #includ

Luogu P5416 [CTSC2016]时空旅行(线段树分治)

题目 简化题意:你需要维护\(n\)个集合,集合元素为二元组\((x,v)\).集合\(i\)的产生方式是以某个原有集合\(p_i\)为样本,扩展或删除一个元素后得到新集合.有\(q\)次询问,每次给出\(y\)并指定一个集合\(i\),要求从集合\(i\)中找出一个元素,最小化\((x?y)^2+v\). 先拆式子\((x-y)^2+v=x^2-2xy+y^2+v\),令其等于\(k\)即\(x^2+y^2-2xy+v=k\). 移项得\(2yx+k=y^2+x^2+v\),可以看作是\((x

【题解】Luogu P5337 [TJOI2019]甲苯先生的字符串

原题传送门 我们设计一个\(26*26\)的矩阵\(A\)表示\(a~z\)和\(a~z\)是否能够相邻,这个矩阵珂以由\(s1\)得出.答案显然是矩阵\(A^{len_{s2}-1}\)的所有元素之和,矩阵快速幂即可 #include <bits/stdc++.h> #define ll long long #define mod 1000000007 using namespace std; inline void write(register int x) { if(!x)putchar

「 Luogu P2574 」 XOR的艺术——线段树

# 解题思路 这题不难,但是原谅我一开始的傻逼想法,一会儿再给大家透露透露. 先说怎么做这题. 显然对于 $0$ 和 $1$ 来说,异或无非也就只有两种变化 异或了奇数次,$0$ 就会变成 $1$,$1$ 就会变成 $0$. 异或了偶数次,$0$ 和 $1$ 都不变. 那只需要在下传标记的时候下传修改了几次就可以. 好,下面说说我那傻逼的操作.我在下传标记的时候没有给子节点的 sum 进行异或,而是只下传了标记,并且在回溯的时候没有更新父节点的 sum 值. 然后我成功的没过样例,然鹅这并不傻逼