这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k(k>2), 使得(m−k)mod6=0即可.
证明如下: 3n(n−1)+1=6(n∗(n−1)/2)+1, 注意到n∗(n−1)/2是三角形数, 任意一个自然数最多只需要3个三角形数即可表示. 枚举需要k个, 那么显然m=6(k个三角形数的和)+k, 由于k≥3, 只要m−k是6的倍数就一定是有解的.
事实上, 打个表应该也能发现规律.
学了下三角形数的性质:
1.任意一个数都可以由三个三角形术表示
2.任何三角形数 * 8 + 1得到一个平方数
3.验证三角形数的公式:
n = (sqrt ( 8 * X + 1 ) - 1) / 2
如果为三角形数那么n为整数切为第n个
三角数具体连接:http://baike.baidu.com/view/1047488.htm
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 100000;
const int INF = 1000000000;
int _list[maxn],cnt = 1,n;
void init(){
while(1){
_list[cnt] = 3 * cnt * (cnt - 1) + 1;
if(_list[cnt] > INF) break;
cnt ++;
}
}
int Find(int value){
return lower_bound(_list + 1,_list + cnt,value) - _list;
}
bool solve(int v){
int l = 1,r = Find(v);
while(l <= r){
if(_list[l] + _list[r] > v)
r --;
else if(_list[l] + _list[r] < v)
l ++;
else
return true;
}
return false;
}
bool can(int n){
int d = (n - 1);
if(d % 6 == 0){
d /= 6;
double dd = (sqrt(8.0 * d + 1.0) - 1.0) / 2;
if(dd == (int)dd)
return true;
}
return false;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
/*
这里说一下,如果暴力找的话时间话费46ms
如果利用判断是否为三角数的性质时间为31ms
*/
/*if(_list[Find(n)] == n){
printf("1\n");
}*/
if(can(n)){
printf("1\n");
}
else{
if((n - 2) % 6 == 0 && solve(n))
printf("2\n");
else{
for(int i = 3; ; i++)
if((n - i) % 6 == 0){
printf("%d\n",i);
break;
}
}
}
}
return 0;
}