性质分析+数位DPCF750G New Year and Binary Tree Paths

Posted psychicboom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性质分析+数位DPCF750G New Year and Binary Tree Paths相关的知识,希望对你有一定的参考价值。

规律找完,不会DP,光荣爆零,身败名裂

而且这还是道原题!!原题!!


从只往一棵子树走的情况考虑

(x)往左走了(z)个儿子,那总和为(xsumlimits_{i=0}^{z}2^i=x(2^{z+1}-1))

考虑从上到下第(y(yin(2,z]))个儿子变成了右儿子,其它不变,则贡献为(xsumlimits_{i=0}^{z}2^i+sumlimits_{i=0}^{z-y}2^i=x(2^z-1)+2^{z-y+1}-1)

然后你稍微看一下会发现,当(z)固定时,(x)只能取(lfloor frac{s}{2^z-1} floor),且只有一种走法

现在考虑(x)的左儿子向左下走了(z1)步,右儿子向左下走了(z2)步的情况

则有(2x(2^{z1}-1)+(2x+1)(2^{z2}-1)+2^{z2}-1+x=(2^{z1+1}+2^{z2+1}-3)x+2^{z2}-1)的贡献

然后枚举了(z1),(z2)后,(x)还是只有一个取值,即(lfloor frac{s}{2^{z1+1}+2^{z2+1}-3} floor)

证明的话就考虑左子树和右子树走相同步,左子树最大的路径和一定小于右子树最小的路径和

然后问题转化成了:用({1,3…,2^{h1}-1})({1,3,…,2^{h2}-1})的元素组成(s-lfloor frac{s}{2^{z1+1}+2^{z2+1}-3} floor*(2^{z1+1}+2^{z2+1}-3))的方案数

(s-lfloor frac{s}{2^{z1+1}+2^{z2+1}-3} floor*(2^{z1+1}+2^{z2+1}-3)=res)

这个(-1)很烦,于是你考虑枚举选了(cnt)个数,然后把所有(2^i-1)转化为(2^i),于是显然(res+cnt)为偶数时才有解

(f[i][j][k])表示当前做到第(i)位,选了(j)个数,这位是否进位的方案数

对于(2^j),设第一个集合是否选这个数的状态为(x(xin{0,1})),第二个集合的选择状态为(y(yin{0,1}))

转移时,要满足(x+y+k)(res+cnt)的第(j)位奇偶性相同

于是有(f[i+1][j+x+y][frac{x+y+k}{2}]leftarrow f[i][j][k])

然后就分类只走一边和两边的情况就行了

因为DRX太强了所以这里贴她的代码,我的代码在这里(大半年前写的,码风巨丑无比)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;++i)
typedef long long ll;
typedef double db;
ll bit[65],f[65][120][2];//在{2,2^2,2^3...2^h1}∪{2,2^2,...2^h2}之间选tot个数,其和==s,                                                                    
inline ll dp(ll s,int tot,int h1,int h2){//应该是{2-1,2^2-1,2^3-1...2^h1-1}∪{2-1,2^2-1,...2^h2-1},但是已经把减一移过去s了
    memset(f,0,sizeof f);f[0][0][0]=1;//在{2,2^2...}中选,2^min(h1,h2)和之前的数可以选两个,f[i][j][k]表示做到第i个数,之前(包括i)选了j个数,对下一位的进位为k
    int ed=log2(s);//能选的最大的数 
    rep(i,1,ed){
        ll d=(s>>i)&1;
        int ed=i*2-2;//在 i之前最多能选多少个 
        rep(j,0,ed) rep(k,0,1)/*上一位是否进位*/rep(p1,0,1)/*左链是否向右走即是否选一个2^i*/rep(p2,0,1)/*右链同理*/if((i<h1||p1==0)&&(i<h2||p2==0)&& (p1+p2+k)%2==d)/*因为x的左右儿子即2^h1和2^h2是肯定要选的*/
        f[i][j+p1+p2][(k+p1+p2)/2]+=f[i-1][j][k]; 
    }
    return f[ed][tot][0];
} 
int main(){
    ll x,s,res,ans=0;
    int ed=0;
    scanf("%lld",&s);
    bit[0]=1;while(bit[ed]<=s) bit[++ed]=bit[ed-1]<<1;
    rep(i,1,ed){//统计一条链的情况 
        if(bit[i]-1>s) break;
        x=s%(bit[i]-1);
        for(int j=i;j>=1;--j) if(x>=bit[j]-1) x-=bit[j]-1;
        if(!x) ++ans;
    }
    rep(h1,1,ed-1){//统计有分叉的情况 
        for(int h2=1;bit[h2]-1<=s&&h2<ed;++h2){//枚举两边的链长 h1  h2 
            x=(s-bit[h2]+1)/(bit[h1+1]+bit[h2+1]-3);
            if(x>0){
                res=(s-bit[h2]+1)%(bit[h1+1]+bit[h2+1]-3);
                if(res==0){//不用向右走 
                    ++ans;continue;
                }
                if(h1==1&&h2==1){//x只选了左儿子x*2和右儿子x*2+1 ,所以是x*5+1 
                    ans+=(s==x*5+1);continue;
                }//有余数说明在某些点要往右走
                rep(i,1,h1+h2) if((res+i)%2==0) ans+=dp(res+i,i,h1,h2);//相当于把减掉的 i个一挪到等式另一边变成加 i个一 
            }
        }
    }
    printf("%lld",ans);
}

以上是关于性质分析+数位DPCF750G New Year and Binary Tree Paths的主要内容,如果未能解决你的问题,请参考以下文章