(数学,大数运算)Consecutively Increasing Sequences_ACdream原创群赛(17)のacmer never retire

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.
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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值