• [TJOI2019]甲苯先生的线段树


    [TJOI2019]甲苯先生的线段树

    首先原题:

    CF750G New Year and Binary Tree Paths 

    方法:

    满二叉树,链长为logn

    考虑枚举lca为x,两个链长h1,h2,

    发现x是唯一确定的!

    找到这个x,

    s减去都走左儿子的贡献,再调整出右儿子

    2^n-1->2^n,变成每一位的0/1更好算!只要知道选择了几个右儿子即可

    然后数位DP

    f[i][j][k],i位,选了j个,有无从上一位来的进位

     

    至于本题:

    多了一个路径编号和

    a,b的lca就是二进制下的lcp(从高位开始)

    暴力枚举即可

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=53;
    ll mi[N],ans,f[N][2*N][2];
    ll d,a,b,c;
    ll calc(int h1,int h2,int us,ll p){
        memset(f,0,sizeof f);
        f[0][0][0]=1;
        int tmp=log2(p);
        for(reg i=0;i<tmp;++i){
            int now=p>>(i+1)&1;
            for(reg j=0;j<=us;++j){
                for(reg k=0;k<=1;++k){
                    if(f[i][j][k])
                    for(reg a=0;a<=1;++a){
                        if(a==1&&(i+1)>h1) continue;
                        for(reg b=0;b<=1;++b){
                            if(b==1&&(i+1)>h2) continue;
                            if((a+b+k)%2!=now) continue;
                            if(j+a+b>us) continue;
                            f[i+1][j+a+b][(a+b+k)/2]+=f[i][j][k];
                        }
                    }
                }
            }
        }
        return f[tmp][us][0];
    }   
    ll wrk(ll s,int d){
        // cout<<" wrk "<<s<<" d "<<d<<endl;
        ans=0;
        for(reg h1=0;h1<=d-1;++h1){
            for(reg h2=0;h2<=d-1;++h2){
                ll tmp=s-mi[h2]+1;
                if(tmp<0) break;
                tmp=tmp/(mi[h1+1]+mi[h2+1]-3);
                ll x=tmp;
                int ceng=log2(x)+1;
                if(ceng+h1>d||ceng+h2>d) continue;
    
                tmp=(mi[h1+1]+mi[h2+1]-3)*x+mi[h2]-1;
                ll ret=s-tmp;
                if(ret<0||x<=0) break;
                if(ret==0) {
                    ++ans;continue;
                }
                // cout<<" h1 "<<h1<<" h2 "<<h2<<" : "<<ret<<" "<<x<<" "<<tmp<<endl;
                for(reg j=0;j<=max(0,h1-1)+max(0,h2-1);++j){
                    if((ret+j)&1) continue;
                    ll lp=calc(max(0,h1-1),max(0,h2-1),j,ret+j);
                    // cout<<" h1 "<<h1<<" h2 "<<h2<<" j "<<j<<" x "<<x<<" = "<<ret+j<<" : "<<lp<<endl;
                    ans+=lp;
                }
            }
        }
        return ans;
    }
    int main(){
        mi[0]=1;
        for(reg i=1;i<=52;++i) mi[i]=mi[i-1]*2;
        int T;
        rd(T);
        while(T--){
            rd(d);rd(a);rd(b);rd(c);
            ll dis=0;
            ll lca=0;
            int e=0;
            int d1=log2(a),d2=log2(b);
            // cout<<" d1 "<<d1<<" d2 "<<d2<<endl;
            while(e<=min(d1,d2)&&((a>>(d1-e))&1)==((b>>(d2-e))&1)){
                lca=lca*2+((a>>(d1-e))&1);++e;
            }
            ll tmp=lca;
            dis=lca;
            // cout<<" lca "<<lca<<" ee "<<e<<endl;
            for(reg i=e;i<=d1;++i){
                tmp=tmp*2+((a>>(d1-i))&1);
                dis+=tmp;
            }
            tmp=lca;
            for(reg i=e;i<=d2;++i){
                tmp=tmp*2+((b>>(d2-i))&1);
                // cout<<" tmp "<<tmp<<endl;
                dis+=tmp;
            }
            if(c==1){
                printf("%lld
    ",dis);
            }
            else printf("%lld
    ",wrk(dis,d)-1);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */
  • 相关阅读:
    Linux学习--线程概念
    菱形继承
    C++类型萃取
    Linux学习--进程创建
    Linux学习--进程概念
    比较全面的gdb调试命令
    再度理解原码、反码、补码
    详谈C++虚函数表那回事(多重继承关系)
    【sparkStreaming】将DStream保存在MySQL
    【sparkStreaming】kafka作为数据源的生产和消费
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10853116.html
Copyright © 2020-2023  润新知