题意:给定一个序列,a[n]=3n(n-1)+1,n>=1,求给定的m(m<=1e9)最少可以用几个a里面的数表示(可以重复)
思路:对答案分类
(1)假定答案为1,则m必定是a中的某一个数,直接查找即可,复杂度O(logn)
(2)假定答案为2,则m必定可以拆分成两个a中的数之和,用两指针分别从头和尾向中间扫,判断是否可以构成m,复杂度O(n)
(3)假定答案大于等于3,设答案为k,即k>=3,则必有m=a[i1]+a[i2]+...+a[ik],由于a[i]=3i(i-1)+1=6[i(i-1)/2]+1,所以有:
m=6[i
1
(i
1
-1)/2+i
2
(i
2
-1)/2+...+i
k
(i
k
-1)/2]+k
所以(m-k)%6==0恒成立,也就是说如果得出了答案k,那么答案一定满足(m-k)%6==0,这是必要性;当k>=3时,令b=(m-k)/6,因为任意一个自然数最多只需要3个三角形数即可表示,所以b=i1(i1-1)/2+i2(i2-1)/2+...+ik(ik-1)/2恒有解,这是充分性。故答案k需满足k>=3且(m-k)%6==0,由于是求最小个数,k从3枚举到第一次满足(m-k)%6==0即可得到答案。
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
|
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <ctime>
#include <deque>
#include <queue>
#include <algorithm>
using
namespace
std;
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define all(a) (a).begin(), (a).end()
void
readInt(){}
void
RI(
int
&X){
scanf
(
"%d"
,&X);}
template
<
typename
...R>
void
RI(
int
&f,R&...r){RI(f);RI(r...);}
void
RIA(
int
*p,
int
*q){
int
d=p<q?1:-1;
while
(p!=q){
scanf
(
"%d"
,p);p+=d;}}
void
print(){cout<<endl;}
template
<
typename
T>
void
print(
const
T t){cout<<t<<endl;}
template
<
typename
F,
typename
...R>
void
print(
const
F f,
const
R...r){cout<<f<<
", "
;print(r...);}
template
<
typename
T>
void
print(T*p, T*q){
int
d=p<q?1:-1;
while
(p!=q){cout<<*p<<
", "
;p+=d;}cout<<endl;}
typedef
pair<
int
,
int
> pii;
typedef
long
long
ll;
typedef
unsigned
long
long
ull;
template
<
typename
T>
bool
umax(T &a,
const
T &b) {
return
a >= b?
false
: (a = b,
true
);
}
/* -------------------------------------------- */
vector<
int
> table;
void
init() {
for
(
int
i = 1; ; i ++) {
ll buf = 3ll * i * (i - 1) + 1;
if
(buf > 1e9 + 7)
break
;
table.pb((
int
)buf);
}
}
bool
chk(
int
x) {
int
l = 0, r = upper_bound(all(table), x - table[0]) - table.begin() - 1;
while
(l < r && table[l] + table[r] != x) {
l ++;
while
(l < r && table[l] + table[r] > x) r --;
}
return
table[l] + table[r] == x;
}
int
main() {
#ifndef ONLINE_JUDGE
freopen
(
"in.txt"
,
"r"
, stdin);
#endif // ONLINE_JUDGE
int
T;
cin >> T;
init();
while
(T --) {
int
x;
RI(x);
if
(find(all(table), x) != table.end()) {
puts
(
"1"
);
continue
;
}
if
(chk(x)) {
puts
(
"2"
);
continue
;
}
for
(
int
k = 3; ; k ++) {
if
((x - k) % 6 == 0) {
printf
(
"%d\n"
, k);
break
;
}
}
}
return
0;
}
|