E - Consecutively Increasing Sequences
Time Limit:
2000/1000MS (Java/Others)
Memory Limit:
128000/64000KB (Java/Others)
Problem Description
给出无限长的序列1,1,3,1,3,5,7,1,3,5,7,9,11,13,15,1,3,5,7,9...,问对于序列的前N个数,所有的连续上升子序列的和是多少.
如N = 6的时候,序列是{1,1,3,1,3,5},它的所有连续上升子序列是{1},{1},{1,3},{3},{1},{1,3},{1,3,5},{3},{3,5},{5},结果为39.
如N = 6的时候,序列是{1,1,3,1,3,5},它的所有连续上升子序列是{1},{1},{1,3},{3},{1},{1,3},{1,3,5},{3},{3,5},{5},结果为39.
Input
多组数据(约1000组),每组数据:
一行N (1 <= N <= 10^9)
Output
对于每个N,输出结果
Sample Input
1 2 6 10
Sample Output
1 2 39 119
Sigma(1..n) = n * (n + 1) / 2
Sigma(1^2 ..n^2) = n * (n + 1) * (2 * n + 1) / 2
Sigma(1^3.. n^3) = n^2*(n + 1)^2 / 4
因为要求序列连续上升,所以只有从1开始的一段才有用,被下一个1隔开的一段完全失效。对于一段从1开始的,我们发现前k项的和是(2 * 1 - 1) + .... + (2 * k - 1) = k^2,所以假设我们枚举每个子序列的终止位置为k的话,枚举它的起始位置为j,那么它们的和就是k ^2-j^2。Sum(k^2 - j^2)(j = 0... k - 1) = k^3 - k * (k - 1) * (2 * k - 1) / 6,然后k从1到序列长度求和即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using
namespace
std;
const
int
SIZE = 7;
const
int
mod = 1000000000;
struct
bignum
{
long
long
a[SIZE];
bignum() {
memset
(a,0,
sizeof
(a));
}
bignum(
long
long
n) {
memset
(a,0,
sizeof
(a));
a[0] = n;
adjust();
}
bignum adjust() {
for
(
int
i = 0; i < SIZE; i ++)
if
(a[i] >= mod) {
a[i + 1] += a[i] / mod;
a[i] %= mod;
}
else
if
(a[i] < 0) {
a[i + 1] --;
a[i] += mod;
}
}
bignum operator * (
const
bignum &p) {
bignum c;
for
(
int
i = 0; i < SIZE; i ++)
for
(
int
j = 0; i + j < SIZE; j ++)
c.a[i + j] += a[i] * p.a[j];
c.adjust();
return
c;
}
bignum operator / (
const
int
x) {
long
long
tmp = 0;
bignum c;
memcpy
(c.a,a,
sizeof
(a));
for
(
int
i = SIZE - 1; i >= 0; i --) {
long
long
p = (tmp * mod + c.a[i]) % x;
c.a[i] = (tmp * mod + c.a[i]) / x;
tmp = p;
}
return
c;
}
bignum operator + (bignum &p) {
bignum c;
for
(
int
i = 0; i < SIZE; i ++)
c.a[i] = a[i] + p.a[i];
c.adjust();
return
c;
}
bignum operator - (bignum &p) {
bignum c;
for
(
int
i = 0; i < SIZE; i ++)
c.a[i] = a[i] - p.a[i];
c.adjust();
return
c;
}
bool
operator == (bignum &p) {
for
(
int
i = 0; i < SIZE; i ++)
if
(a[i] != p.a[i])
return
false
;
return
true
;
}
void
output() {
int
i = SIZE - 1;
for
(i; i >= 0; i --) {
if
(a[i])
break
;
}
printf
(
"%lld"
,a[i]);
for
(i = i - 1; i >= 0; i --)
printf
(
"%09lld"
,a[i]);
printf
(
"\n"
);
}
};
bignum cal1(
int
n)
{
return
bignum(n) * bignum(n + 1) / 2;
}
bignum cal2(
int
n)
{
return
bignum(n) * bignum(n + 1) * bignum(2 * n + 1) / 6;
}
bignum cal3(
int
n)
{
return
bignum(n) * bignum(n) * bignum(n + 1) * bignum(n + 1) / 4;
}
bignum cal(
int
n)
{
bignum tot = cal3(n);
bignum sub1 = bignum(2) * cal3(n);
bignum sub2 = bignum(3) * cal2(n);
bignum sub3 = cal1(n);
sub1 = sub1 + sub3;
sub1 = sub1 - sub2;
sub1 = sub1 / 6;
return
tot - sub1;
}
long
long
baoli(
int
n)
{
long
long
ans = 0;
int
now = 0;
while
(n) {
int
m = min(1 << now,n);
n -= m;
for
(
long
long
i = 1; i <= m; i ++)
for
(
long
long
j = 0; j < i; j ++)
ans += i * i - j * j;
now ++;
}
return
ans;
}
void
solve(
int
n)
{
//int tn = n;
bignum ans;
int
now = 0;
while
(n) {
int
m = min(1 << now,n);
n -= m;
bignum tmp = cal(m);
now ++;
ans = ans + tmp;
}
ans.output();
//long long tans = baoli(tn);
//bignum test = bignum(tans);
}
int
main()
{
int
n;
while
(
scanf
(
"%d"
,&n) != EOF) solve(n);
return
0;
}
|