hdu 5312 Sequence

跟風遠走 提交于 2020-03-26 02:38:25
问题描述
Soda习得了一个数列, 数列的第n(n≥1)项是3n(n-1)+1. 现在他想知道对于一个给定的整数m, 是否可以表示成若干项上述数列的和. 如果可以, 那么需要的最小项数是多少?
 
例如, 22可以表示为7+7+7+1, 也可以表示为19+1+1+1
输入描述
输入有多组数据. 第一行有一个整数T(1≤T≤104 ), 表示测试数据组数. 然后对于每组数据:
 
一行包含1个整数 m(1≤m≤109).
输出描述
对于每组数据输出最小花费.
输入样例
10
1
2
3
4
5
6
7
8
22
10
输出样例
1
2
3
4
5
6
1
2
4
4
 

对于这种题,首先一开始就要对给出的公式进行研究,从这里入手是正道。

分析公式 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;
}

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!