题意
你有
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);
}
}