• [CF750G] New Year and Binary Tree Paths


    题目链接

    简单的

    设从节点(x)开始不断往左儿子走h-1步,则编号和为(xsum_{i=0}^{h-1}2^i=x(2^h-1))

    若倒数第(i)步走向的是右儿子,则编号和会增加(sum_{j=0}^{i-1}2^j=2^i-1)

    这样,从(x)往下走形成的长为(h)的链中,其中倒数(i,iin T)步时走向右儿子,倒数(i,i otin T)步走向左儿子,这样得到的编号和为

    [x(2^h-1)+sum_{iin T}2^i-|T|=S ]

    (L=lfloorfrac{S}{2^h-1} floor),显然(|T|<hlelog_2(S+1),xle L)。又因为

    [(L-1)(2^h-1)+sum_{iin T}2^i-|T|le S-(2^h-1)+(2^h-h-1)\ =S-h<S ]

    (x>L-1)进而(x=L),或称对每个(h)有唯一的(x=L),那么方案数为方程(sum_{iin T}2^i=S+|T|+L(2^h-1))的解的个数。(这显然最多只有一组解)

    组合的

    从节点(x)的左右儿子出发的两天简单链分别表示为((h_0,T_0),(h_1,T_1)),总的编号和

    [x+2x(2^{h_0}-1)+(2x+1)(2^{h_1}-1)+sum_{iin T_0}2^i+sum_{iin T_1}2^i-|T_0|-|T_1|\ =x(2^{h_0+1}+2^{h_1+1}-3)+2^{h_1}-1+sum_{iin T_0}2^i+sum_{iin T_1}2^i-|T_0|-|T_1|=S ]

    大胆猜想(h_0,h_1)确定时有唯一的(x=lfloorfrac{S-2^{h_1}+1}{2^{h_0+1}+2^{h_1+1}-3} floor)

    接着问题转变为在({2^1,2^2,cdots,2^{h_0-1}},{2^1,2^2,cdots,2^{h_1-1}})中一共选取(n)个数之和等于(S-(cdots)+n)(QAQ)的方案数。

    考虑枚举(n),设(f[i,j,0/1])表示考虑完前(i)个指数后,已经选了(j)个数字,这一位(二进制末尾第(i+1)位)为是否进位的方案数。其中(f[0,0,0]=1)

    答案是(sum_{h_0,h_1}(sum_n f[max(h_0,h_1),n,0]))。时间复杂度(O(log_2^5S))

    #include <bits/stdc++.h>
    #define LL long long 
    using namespace std;
    const int N=53;
    
    LL S,L,ans;
    LL P[N]={1};
    LL f[N][N*2][2];
    
    int main() {
    	scanf("%lld",&S); L=log2(S+1);
    	for(int i=1; i<N; ++i) P[i]=P[i-1]<<1;
    	for(int h=1; h<=L; ++h) {
    		LL x=S%(P[h]-1);
    		for(int i=h; i; --i) if(x>=P[i]-1) x-=P[i]-1;
    		ans+=(!x);
    	}
    	for(int h0=1; h0<L; ++h0)
    	for(int h1=1; S+1-P[h1]>=P[h0+1]+P[h1+1]-3; ++h1) {
    		LL x=(S+1-P[h1])/(P[h0+1]+P[h1+1]-3);
    		LL r=(S+1-P[h1])%(P[h0+1]+P[h1+1]-3);
    		if(!r) {ans++; continue;}
    		if(h0==1&&h1==1) {ans+=(S==x*5+1); continue;}
    		for(int n=1; n<=h0+h1; ++n) {
    			LL C=r+n,L=log2(C);
    			if(C&1) continue;
    			memset(f[0],0,sizeof f[0]); f[0][0][0]=1;
    			for(int i=1; i<=L; ++i) {
    				int d=(C>>i)&1; memset(f[i],0,sizeof f[i]);
    				for(int j=0; j<=i+i-2&&j<=n; ++j)
    				for(int k=0; k<2; ++k) if(f[i-1][j][k]) 
    					for(int x=0; x<2; ++x) if(!x||i<h0)
    					for(int y=0; y<2; ++y) if(!y||i<h1) 
    						if(((k+x+y)&1)==d) f[i][j+x+y][(k+x+y)>>1]+=f[i-1][j][k];
    			}
    			ans+=f[L][n][0];
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    不知道1K+ms是怎么跑出来的

  • 相关阅读:
    Oracle查看表或者视图的定义语句
    SpringMvc使用FastJson做为json的转换器(注解方式)
    Centos7安装vsftpd
    linux下的find文件查找命令与grep文件内容查找命令
    Centos7虚拟机下配置静态IP
    替换Jar包内的文件
    Java 获取本机IP地址
    RecyclerView 与 ItemTouchHelper 实现拖拽效果
    Android 开发日常积累
    Android 自定义 View 知识点
  • 原文地址:https://www.cnblogs.com/nosta/p/10829973.html
Copyright © 2020-2023  润新知