思路:这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断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的倍数就一定是有解的.
事实上, 打个表应该也能发现规律.
两边向中间找扫描的时候落了等号错了好多次,忘了数相等的时候也可以,最后找最小的k,直接取余就行,最少是从3开始的。
#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define INF 9999999999
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef unsigned long long llu;
typedef long long ll;
const int maxd=18258+5;
///=========================
int s[maxd];
int m;
void table()
{
s[0]=0;
for(int i=1;i<maxd;i++)
s[i]=3*i*(i-1)+1;
}
bool ok1(int x)
{
int pos=lower_bound(s,s+maxd,x)-s;
if(s[pos]==x) return true;
return false;
}
bool ok2(int x)
{
if((x-2)%6) return false;
int l=1,r=maxd-1;
while(l<=r)
{
if(s[l]+s[r]<x)
l++;
else if(s[l]+s[r]>x)
r--;
else return true;
}
return false;
}
int main()
{
int kase;
// freopen("1.txt","r",stdin);
table();
scanf("%d",&kase);
while(kase--)
{
scanf("%d",&m);
if(ok1(m))
printf("1\n");
else if(ok2(m))
printf("2\n");
else
{
// for(int k=3;k<=m;k++)
// if((m-k)%6==0)
// {
// printf("%d\n",k);
// break;
// }
printf("%d\n",(m-3)%6+3);
}
}
return 0;
}