Property Analysis [DP] + digital CF750G New Year and Binary Tree Paths

Find the law, has not DP, glorious burst zero, and ruin

And this is the path of the original title! ! The original title! !


From the only case to go to consider a subtree

\ (X \) left to go \ (Z \) son that the sum of \ (x \ sum \ limits_ { i = 0} ^ {z} 2 ^ i = x (2 ^ {z + 1} - 1)\)

Considered from top to bottom of \ (y (y \ in ( 2, z]) \) son son becomes the right, the other constant, the contribution to the \ (x \ sum \ limits_ { i = 0} ^ { z} 2 ^ i + \ sum \ limits_ {i = 0} ^ {zy} 2 ^ i = x (2 ^ z-1) + 2 ^ {zy + 1} -1 \)

Then you will find that a little look, when \ (Z \) fixed, \ (X \) can only take \ (\ lfloor \ FRAC {S} {2}. 1-Z ^ \ rfloor \) , and only one down law

Now consider \ (x \) left his son left grumbled \ (z1 \) steps, the son left and right laid down \ (z2 \) case step

There \ (2x (2 ^ {z1 } -1) + (2x + 1) (2 ^ {z2} -1) + 2 ^ {z2} -1 + x = (2 ^ {z1 + 1} +2 ^ {z2 + 1} -3) x + 2 ^ {z2} -1 \) contributed

Then enumerating \ (Z1 \) , \ (Z2 \) after, \ (X \) or only a value, i.e., \ (\ lfloor \ frac {s } {2 ^ {z1 + 1} + 2 ^ { z2 + 1} -3} \ rfloor \)

Proof, then consider the left subtree and right subtree go-phase synchronous, left subtree must be smaller than the largest of the path and the path of least and the right subtree

Is then transformed into the problem: using \ (\ {1,3 ..., 2 ^ {h1} -1 \} \) and \ (\ {1,3, ..., 2 ^ {h2} -1 \} \) of elements \ (s- \ lfloor \ frac { s} {2 ^ {z1 + 1} + 2 ^ {z2 + 1} -3} \ rfloor * (2 ^ {z1 + 1} + 2 ^ {z2 + 1 } -3) \) is the number of programs

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

The \ (--1 \) annoying, so you consider enumeration chose \ (cnt \) number, then all the \ (2 ^ i-1 \ ) into \ (2 ^ i \) , then obviously \ (res + cnt \) is a solvable if an even number

Set \ (f [i] [j ] [k] \) represents the current section do \ (I \) bits, the selected \ (J \) number, whether the number of the programs carry

For \ (2 ^ J \) , whether the set is selected from a first set state this number is \ (X (X \ in \ {0,1 \}) \) , the second select state is set \ (Y (y \ in \ {0,1 \ }) \)

When the transfer, to meet the \ (x + y + k \ ) and \ (res + cnt \) of \ (J \) bit parity are the same

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

Then the classification and walked only one side on both sides of the situation on the line

Because the DRX too strong here so she posted the code in my code here (half a year ago to write, very ugly giant wind code)

#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);
}

Guess you like

Origin www.cnblogs.com/PsychicBoom/p/11774327.html