这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k
(k > 2)k(k>2),
使得(m - k) mod 6 =
0(m?k)mod6=0即可.
证明如下: 3n(n-1)+1 =
6(n*(n-1)/2)+13n(n?1)+1=6(n?(n?1)/2)+1,
注意到n*(n-1)/2n?(n?1)/2是三角形数,
任意一个自然数最多只需要3个三角形数即可表示. 枚举需要kk个,
那么显然m=6(km=6(k个三角形数的和)+k)+k,
由于k \ge 3k≥3,
只要m-km?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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-14 12:22:42