CodeForces 750G. New Year and Binary Tree Paths

来源:互联网 发布:zepto.js菜鸟教程 编辑:程序博客网 时间:2024/06/04 23:30

The New Year tree is an infinite perfect binary tree rooted in the node 1. Each node v has two children: nodes indexed (2·v) and (2·v + 1).

Polar bears love decorating the New Year tree and Limak is no exception. As he is only a little bear, he was told to decorate only one simple path between some pair of nodes. Though he was given an opportunity to pick the pair himself! Now he wants to know the number of unordered pairs of indices (u, v) (u ≤ v), such that the sum of indices of all nodes along the simple path between u and v(including endpoints) is equal to s. Can you help him and count this value?

Input

The only line of the input contains a single integer s (1 ≤ s ≤ 1015).

Output

Print one integer, denoting the number of unordered pairs of nodes indices defining simple paths with the sum of indices of vertices equal to s.

Example
input
10
output
4
Note

In sample test, there are 4 paths with the sum of indices equal to 10:

题意:给一棵无限二叉树如上图所示,给定N,统计有多少条路径经过点的编号之和为N
题解:
我说这题是数位dp+暴力你信吗QAQ
这题的性质啊 excited
性质1:x的子节点是x << 1,x << 1 | 1;(显然)
性质2:在二叉树上的点x,1到x的点的编号和为2 * x - popcount( x );
性质3:一条路径的由lca和两边组成,如果两边的终点离lca的距离已知,那么lca唯一确定;
考虑证明性质3
一条路径把lca所在节点的贡献减掉 那么二叉树将变成这样:
                0
          0            1
      0     1      2      3
    0  1  2   3   4  5   6  7
虽然有0,仍然满足性质2
那么lca的贡献是多少呢 假设深度为a
lca + lca * 2 + lca * 4 ... + lca * 2 ^ a = lca * 2 ^ ( a + 1 ) - lca
总的就是mul * lca = lca * ( 2 ^ ( a + 1 ) - 1 + 2 ^ ( b + 1 ) - 1 - 1 )(最后那个-1是根节点多算了一次)
若lca的贡献+其他贡献=n 则lca-1之后,及时其他贡献达到上界,(lca-1)的贡献+其他贡献<n(很好证明,考虑每个数最高位大于所有低位之和)
故剩下的就是两边的数 右边的1不好做 把右边的1的贡献去掉
剩下的树两边相等了, 剩下的n为now = n - mul * lca - ( 2 ^ b - 1 )
现在问题变成了 选两个数a, b, 要求a < 2 ^ ( a - 1 ), b < 2 ^ ( b - 1 )(因为lca下一层已经变成0了,深度要-1)
a, b的位数是随意的, 因为前导0在上面的树中是合法的
且 2 * ( a + b ) - popcount( a ) - popcount( b ) = now,枚举popcount(a)+popcount(b),二进制位下数位dp即可
数位dp时可以把popcount(a)+popcount(b)一起算
复杂度?实测n=1e15时本机跑1.2s
吐槽:1、由于看错英文题解导致认为枚举的是深度a,b,浪费一中午+一下午(英语很重要啊2333)
      2、一直以为把lca变成1再算,发现lca算不出来,前导0也没法算,然后就成功浪费一晚上
       (估计就只有我这么菜的才会出现这种情况吧)

#include <bits/stdc++.h>using namespace std;typedef long long LL;LL n, ans;LL f[140][2],g[140][2];LL dp(int one, int lena, int lenb, LL sum){for( int j = 0 ; j <= one ; j++ )f[ j ][ 0 ] = f[ j ][ 1 ] = 0;f[ 0 ][ 0 ] = 1;for( int i = 0 ; ( 1LL << i ) <= sum ; i++ ){for( int j = 0 ; j <= one ; j++ )g[ j ][ 0 ] = f[ j ][ 0 ], f[ j ][ 0 ] = 0,g[ j ][ 1 ] = f[ j ][ 1 ], f[ j ][ 1 ] = 0;for( int j = 0 ; j <= 1 ; j++ ) if( i < lena || !j )for( int k = 0 ; k <= 1 ; k++ ) if( i < lenb || !k )for( int l = 0 ; l <= 1 ; l++ ){int d = j + k + l;if( ( ( sum >> i ) & 1 ) ^ ( d & 1 ) ) continue;for( int m = 0 ; m + j + k <= one ; m++ )f[ m + j + k ][ d >> 1 ] += g[ m ][ l ];}}return f[ one ][ 0 ];}int main(){cin >> n;for( int i = 0 ; i <= 58 ; i++ )for( int j = 0 ; j <= 58 ; j++ ){LL mul = ( 1LL << i + 1 ) + ( 1LL << j + 1 ) - 3;if( n < mul ) break;LL now = n % mul - ( 1LL << j ) + 1;if( now < 0 ) continue;int cnt = i + j;for( int k = now & 1 ; k <= cnt ; k += 2 ){LL tot = now + k;ans += dp( k, i - 1, j - 1, tot >> 1 );}}cout << ans << endl;}


0 0
原创粉丝点击