【HDU 5312】Sequence(数学问题)

来源:互联网 发布:小游戏编程java 编辑:程序博客网 时间:2024/05/16 15:27

这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k (k > 2)k(k>2), 使得(m - k) mod 6 = 0(mk)mod6=0即可.

证明如下: 3n(n-1)+1 = 6(n*(n-1)/2)+13n(n1)+1=6(n(n1)/2)+1, 注意到n*(n-1)/2n(n1)/2是三角形数, 任意一个自然数最多只需要3个三角形数即可表示. 枚举需要kk个, 那么显然m=6(km=6(k个三角形数的和)+k)+k, 由于k \ge 3k3, 只要m-kmk是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;}

0 0