对于这种题,首先一开始就要对给出的公式进行研究,从这里入手是正道。
分析公式 3n(n−1)+1 ,若给出一个数n,假设要k个3n(n−1)+1加起来得到n,即 3n(n-1)k+k=n,注意到3n(n-1)k是6的倍数,那么求的是满足(n-k)%6==0的最小的k。还有就是要注意到1、2要特判,即k要从3开始枚举
打表发现规律了就好做了、 当n%6==1 时要考虑能否由1个数组成在表中找到就可以 否则就需要7项的和了(规律跑个程序或者列举一些数就发现了)
当n%6==2时 要考虑能否由2个数组成 根据表中数据列举一些数(跑个程序更快更简洁)会发现只有2和8两种情况
剩下的就注意一下是6的倍数的直接输出6否则输出n%6即可
/*附上渣渣程序
#include<stdio.h>
int main()
{
int i, j;
for(i = 7; i <= 100; i++)
{
for(j = 1; j < 10; j++)
{
if((i-j) % 6 == 0 && i != j && i%6==1)
printf("%d %d\n", i, j);
}
}
for(i = 7; i <= 100; i++)
{
for(j = 1; j < 10; j++)
{
if((i-j) % 6 == 0 && i != j && i%6==2)
printf("%d %d\n", i, j);
}
}
return 0;
}
*/
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int oo = 0x3f3f3f3f;
const int maxn = 1e6+7;
const int mod = 1e9+7;
int Soda[maxn]={1}, id;///id为最后一个数的下标
void init()///打表
{
for(int i=1; i<=20000; i++)
{
Soda[i]=3*i*(i-1)+1;
if(Soda[i] >= mod-7) {id = i; break;}
}
}
int Search(int left, int right, int x)///二分查找
{
int mid = (left+right)/2;
if(Soda[mid] == x) return 1;
if(left > right) return 0;
if(Soda[mid] < x) return Search(mid+1, right, x);
else return Search(left, mid-1, x);
}
int main()
{
init();///打表
int T, i, n, ans;
// for(i = 0; i < 20; i++)
// printf("%d\n", Soda[i]);
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
if(n%6==1)
{
if(Search(0, id, n)) ans = 1;
else ans = 7;
}
else if(n%6==2)
{
int ok = 0, p = id;
for(i = 1; i <= p; i++)
{
while(Soda[i] + Soda[p] > n)
p--;
if(Soda[i]+Soda[p] == n)
{
ok = 1;
break;
}
}
if(ok) ans = 2;
else ans = 8;
}
else
{
ans = n%6;
if(ans == 0) ans = 6;
// ans = (n-1)%6+1;
}
printf("%d\n", ans);
}
return 0;
}