本题要求构造出来的有根二叉树的所有导出子图是一颗满二叉树的数目最多是多少?那么显而易见必须是一个完全二叉树。
那么问题就回到了给你一个完全二叉树有多少个节点,求完全二叉树里面有多少个导出子图是满二叉树的数目。
首先介绍官方题解的思路:
官方题解将问题进行拆分,首先完全二叉树除了最后一层上面的一定是一个满二叉树。那么就上面这个满二叉树而言,每一个的大小就是i*(n-i+1) (i是层数,n是慢二叉树的高度)。
那么剩下的就是对于最后一层的处理,对于最后一层,最后一层的个数为2的倍数的时候,那么他可以增加的满二叉树的个数为2*(m)-1(m是2的倍数)。那么有这个规律可以推广到使用二进制位去寻找某个2的倍数。
#include <bits/stdc++.h> using namespace std; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,a,n) for(int i=n;i>=a;i--) #define pb push_back #define fs first #define sc second typedef long long ll; typedef double db; typedef pair<int,int> pii; const ll mod=1e9+7; ll n, T; int main() { cin>>T; while (T--) { scanf("%lld", &n); ll man = 0; while ((1ll<<man)-1<=n) { man++; } man--; ll ans = 0; rep(i,1,man) { ans = (ans+(man-i+1ll)*(1ll<<(i-1)))%mod; } ll rem = n-((1ll<<man)-1); rep(i,0,60) { if (rem&(1ll<<i)) { ans = (ans+(1ll<<(i+1))-1ll)%mod; } } printf("%lld\n", ans); } return 0; }看到通过的人代码的思路:
这是一个比官方题解更为简单地思路,如果我们从最后一位向下看的话,可以看出来首先最后一部分也就是从父亲节点到该节点都是满二叉树个数为1的情况(n-1)/2*1。那么延伸到上一个父亲节点也是同样的规律只是满二叉树的个数因为高度的增加而增加了(n-1)/2*2。一次类推算到根就可以了。
//-----------------> #include<bits/stdc++.h> //<----------------- #include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<vector> #include<set> //-----------------> //ios::sync_with_stdio(false); //ios_base::sync_with_stdio(false); //cin.tie(0); //cout.tie(0); //<----------------- using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 2e5+5; const int INF = 0x3f3f3f3f; const int MOD = 1e9+7; int main(){ int T; cin >> T; while(T--){ ll n; cin >> n; ll y = 1; ll ans = 0; while(1){ if(n == 0){ break; } ll t = n; n = n - 1; n = n / 2; ans += (t - n) * y; ans = ans % MOD; y++; } cout << ans << endl; } return 0; }