Codeforces #639(div2) [B. Card Constructions]

题意

你有n张扑克牌 你需要用这n张扑克牌不断搭出如下图的最高扑克金字塔,直到搭不出扑克金字塔

图例

现在需要你求出这n张扑克牌按此规则可以搭出的扑克金字塔的个数

输入

输入一个t(1<=t<=1000),代表t组数据

每组数据有一个n(1<=n<=1e9),代表该次你拥有n张扑克牌

保证所有n的和不超过1e9

输出

每组输出一个数代表可搭金字塔的个数

示例

输入 输出
5 1
3 2
14 1
15 3
24 0
1

思路

可以看出各层的扑克牌数构成等差数列(相邻层之间牌数相差3),那么金字塔所需的牌数就是等差数列的前n项和。

所以没想会不会卡时间直接套公式,先打表,找出牌数超过1e9的金字塔层数,然后暴力公式法:

const int MOD = 1e9 + 7;
	int i;			
	for (; i <= 50000; i++)
    {
        maxn[i] = (i * (3 * i + 1)) / 2;
        //debug(maxn[i]);
        if ((i * (3 * i + 1)) / 2 > MOD)
            break;
    }
    i--;

后面学长提醒了递推时间更少,所以对代码进行了优化(所幸这次官方没卡时间:D)

最后贴出我滴代码:

code

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <queue>
#include <cmath>
#include <string.h>
#include <cstring>
#include <algorithm>
#define s(a, n) memset(a, n, sizeof(a))
#define g(a, max) fgets(a, max, stdin)
#define debug(a) cout << '#' << a << '#' << endl
using namespace std;
const unsigned long long MOD = 1e9 + 7;

int ans;
int maxn[500000];                       //maxn记录各金字塔所需牌数
int i = 2;                              //i记录最大层数

void f(long long x)
{
    for (int l = i; l >= 1; l--)        //从最大层数开始
    {
        if (x >= maxn[l])               //如果大于maxn
        {
            x -= maxn[l];               //扣掉
            ans++;                      //塔数加一
            f(x);                       //递归
            break;
        }
        else
            continue;
    }
    return;                             //找完返回
}

int main()
{
    long long n;
    int l = 1;
    bool fi = true;
    int fl[30000];                      //记录各层数所需牌数
    fl[1] = 2;
    maxn[1] = 2;
    for (int l = 2; l < 26000; l++)     //打表得知最大层数越为258**,上限设为26000
        fl[l] = fl[l - 1] + 3;          //每层比前一层多3张牌
    for (; i < 26000; i++)
    {
        maxn[i] = maxn[i - 1] + fl[i];  //每个金字塔比前一个多第i层
        //debug(maxn[i]);
        if (maxn[i] >= MOD)             //如果大于1e9+7,break
            break;
    }
    i--;                                //i--,保证记录为最大层数
    //debug(i);
    int t;
    scanf("%d", &t);
    while (t--)
    {
        ans = 0;
        scanf("%lld", &n);
        f(n);                           //计算塔数
        if (fi)                         //输出 如果为第一行 不输出换行符
        {
            fi = !fi;
            printf("%d", ans);
        }
        else
            printf("\n%d", ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_46144509/article/details/105969755
今日推荐