性质分析+数位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的主要内容,如果未能解决你的问题,请参考以下文章
CF750G New Year and Binary Tree Paths(DP)
Codeforces908G. New Year and Original Order
CF908G New Year and Original Order