题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5312
解题思路:
官方题解:
这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断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的倍数就一定是有解的.
事实上, 打个表应该也能发现规律.
比赛的时候并没有发现这规律,只是将20000个数据打出来,然后再二分搜索,后来看了被别人hack的数据,才知道,有这回事。。。这怪当时太年轻,啥都不知道。。。也说明了自己打表时并没认真找规律。。。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a[20005];
void solve(ll n){
if(n % 6 == 0){
printf("6\n");
return;
}
else if(n % 6 == 1){
if(*lower_bound(a+1,a+20001,n) == n)
printf("1\n");
else
printf("7\n");
}
else if(n % 6 == 2){
int flag = 0;
for(int i = 0, j = 20000; i <= 20000 && a[i] < n ; i++){
while(j > 0 && a[i] + a[j] > n)
j--;
if(j > 0 && a[i] + a[j] == n){
printf("2\n");
flag = 1;
break;
}
}
if(!flag)
printf("8\n");
return;
}
else
printf("%lld\n",n % 6);
}
int main(){
for(ll i = 1; i <= 20000; i++){
a[i] = 3 * i * (i-1) +1;
}
int T;
scanf("%d",&T);
while(T--){
ll m;
scanf("%lld",&m);
solve(m);
}
return 0;
}