题目链接:点击打开链接
这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断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==1时用二分找出结果求k==2时,对于一个有序的数组,求两个值的和是不是n,用两个指针,一个指向头,一个指向为,不断向另一个方向逼近,就可以找到是否存在和为n
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int a[21000] ;
void init() {
for(int i = 1 ; i <= 20000 ; i++) {
a[i] = 3*i*(i-1)+1 ;
}
}
int binSearch(int x,int high){
int low = 1 , mid , k ;
while( low <= high ) {
mid = (low+high)/2 ;
if( a[mid] <= x ) {
k = mid ;
low = mid + 1 ;
}
else
high = mid - 1 ;
}
return k ;
}
int main() {
int t , m , n , k , i , j , l , r ;
init() ;
scanf("%d", &t) ;
while( t-- ) {
scanf("%d", &m) ;
n = binSearch(m,20000) ;
if( a[n] == m ) {
printf("1\n") ;
continue ;
}
l = 1 ; r = n ;
while( l <= r ) {
if( a[l]+a[r] == m ) break ;
if( a[l]+a[r] < m ) l++ ;
else r-- ;
}
if( l <= r ) {
printf("2\n") ;
continue ;
}
k = 3 ;
while( 1 ) {
if( (m-k)%6 == 0 ) break ;
else k++ ;
}
printf("%d\n", k) ;
}
return 0 ;
}