HDU 5587 数学
2015-11-29 16:50
288 查看
Array Accepts: 112 Submissions: 324
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
问题描述
Vicky是个热爱数学的魔法师,拥有复制创造的能力。
一开始他拥有一个数列{1}。每过一天,他将他当天的数列复制一遍,放在数列尾,并在两个数列间用0隔开。Vicky想做些改变,于是他将当天新产生的所有数字(包括0)全加1。Vicky现在想考考你,经过100天后,这个数列的前M项和是多少?。
输入描述
输入有多组数据。
第一行包含一个整数T,表示数据组数。T. \left( 1 \leq T \leq 2 * {10}^{3} \right)(1≤T≤2∗10
3
)
每组数据第一行包含一个整数M. \left( 1\leq M \leq {10}^{16} \right)(1≤M≤10
16
)
输出描述
对于每组数据输出一行答案.
输入样例
3
1
3
5
输出样例
1
4
7
题解:
我们可以发现,可以把这个数列按一个满二叉树的形式组织起来,a1 = 1,a2 = 1,a3 = 2…这颗树任何一个节点的左儿子等于父亲节点,而右儿子等于父亲节点加1.
1,我们令An为这棵树每一层的节点和。由于题目的复制关系可知,A[n+1] = 2*A
+2^(n-1).
2, 我们用Sn表示An的前n项和,由An的递推公式可知S[n+1]-A[1] = 2*S
+ 2^n - 1.即为S[n+1]= 2*S
+ 2^n。由此公式即可把每一个满子数的前n项和求出来。例如S[3]就表示了前三层所有节点的和。
3,假如我们要求n = 28(图中黑笔表示的数字)用sum[28]表示我们要求的结果。那么可以知道这个结果由两部分组成,一个是S[3](因为28 > 2^4-1),另一个是在第四层的剩余数列和1,2,2,3,2,3,3,4,2,3,3,4,3。
4,求第四层的数列和时,由题目的构造规则可知。当第四层每一项都减1时变为0,1,1,2,1,2,2,3,1,2,2,3,2,总共13个数,就变为了求sum[12].
5,然后求sum[12]
重复上述步骤。当n == 0或者n是满树的最右下方结点时返回。
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
问题描述
Vicky是个热爱数学的魔法师,拥有复制创造的能力。
一开始他拥有一个数列{1}。每过一天,他将他当天的数列复制一遍,放在数列尾,并在两个数列间用0隔开。Vicky想做些改变,于是他将当天新产生的所有数字(包括0)全加1。Vicky现在想考考你,经过100天后,这个数列的前M项和是多少?。
输入描述
输入有多组数据。
第一行包含一个整数T,表示数据组数。T. \left( 1 \leq T \leq 2 * {10}^{3} \right)(1≤T≤2∗10
3
)
每组数据第一行包含一个整数M. \left( 1\leq M \leq {10}^{16} \right)(1≤M≤10
16
)
输出描述
对于每组数据输出一行答案.
输入样例
3
1
3
5
输出样例
1
4
7
题解:
我们可以发现,可以把这个数列按一个满二叉树的形式组织起来,a1 = 1,a2 = 1,a3 = 2…这颗树任何一个节点的左儿子等于父亲节点,而右儿子等于父亲节点加1.
1,我们令An为这棵树每一层的节点和。由于题目的复制关系可知,A[n+1] = 2*A
+2^(n-1).
2, 我们用Sn表示An的前n项和,由An的递推公式可知S[n+1]-A[1] = 2*S
+ 2^n - 1.即为S[n+1]= 2*S
+ 2^n。由此公式即可把每一个满子数的前n项和求出来。例如S[3]就表示了前三层所有节点的和。
3,假如我们要求n = 28(图中黑笔表示的数字)用sum[28]表示我们要求的结果。那么可以知道这个结果由两部分组成,一个是S[3](因为28 > 2^4-1),另一个是在第四层的剩余数列和1,2,2,3,2,3,3,4,2,3,3,4,3。
4,求第四层的数列和时,由题目的构造规则可知。当第四层每一项都减1时变为0,1,1,2,1,2,2,3,1,2,2,3,2,总共13个数,就变为了求sum[12].
5,然后求sum[12]
重复上述步骤。当n == 0或者n是满树的最右下方结点时返回。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <sstream> #define f(i,a,b) for(int i = a;i<=b;i++) #define fi(i,a,b) for(int i = a;i<=b;i--) using namespace std; #define LEN 20 #define MOD 10000 long long G[60],a2[60]; long long dfs(long long k){ if(k == 0) return 0; long long i,j; for(i = 1;;i++)if(a2[i]>=k) break; if(a2[i] == k) return G[i]; long long cnt = i-1; long long sum = G[cnt] + k - a2[cnt]; return sum + dfs(k - a2[cnt] - 1); } int main() { // freopen("data.in","r",stdin); // freopen("data.out","w",stdout); int N; long long kk = 2; G[1] = 1; a2[1] = 1; f(i,1,58){ G[i+1] = 2*G[i] + kk; kk*=2; a2[i+1] = kk - 1; } scanf("%d",&N); while(N--){ long long n; scanf("%lld",&n); printf("%lld\n",dfs(n)); } return 0; }