这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k (k > 2)(k>2), 使得(m - k) mod 6 = 0即可.
证明如下: 3n(n-1)+1 = 6(n*(n-1)/2),注意到n*(n-1)/2是三角形数, 任意一个自然数最多只需要3个三角形数即可表示(高斯发现). 枚举需要k个, 那么显然m=6*(k个三角形数和)+k, 由于k≥3, 只要m-k是6的倍数就一定是有解的.
事实上, 打个表应该也能发现规律.
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson k<<1, L, mid
#define rson k<<1|1, mid+1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
ll a[1000000];
int count1;
int main(){
mem0(a);
int m;
for(int i=1;(ll)3*i*(i-1)+1<=1000010000;i++){
a[i]=3*i*(i-1)+1;
m=i;
}
int t;
int n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
if(*lower_bound(a+1,a+m+1,n)==n){
printf("1\n");
continue;
}
int p=1;
int flag=0;
if((n-2)%6==0){ //两个如果可能的话,则 (n-2)%6==0;
while(2*a[p]<=n){
if(*lower_bound(a+1,a+m+1,n-a[p])==n-a[p]){
printf("2\n");
flag=1;
break;
}
p++;
}
}
if(flag==1)
continue;
for(int i=3;;i++){
if((n-i)%6==0){
printf("%d\n",i);
break;
}
}
}
return 0;
}