纸牌金字塔
题目描述:
高度为1的纸牌金字塔是通过将两张纸牌彼此相对放置而构成的。 对于h > 1,通过将高度为h-1的卡片金字塔放置在底座上来构建高度为h的卡片金字塔。底座由高度为1的h金字塔和顶部为h-1的卡片组成。 例如,高度为1,2和3的纸牌金字塔如下所示

您从N张牌开始,然后建造最高的金字塔。 如果有剩余的纸牌,则可以使用剩余的纸牌建立最高的金字塔。 您重复此过程,直到不可能建造另一个金字塔。 最后,您将建造多少座金字塔?
输入:
第一行一个整数t表示数据组数(1≤t≤1000)
每组数据一行包括一个整数n表示纸牌的数量。(1≤n≤1e9)
输出:
每组数据一行表示答案
样例输入:
5
3
14
15
24
1
样例输出:
1
2
1
3
0
思路:
我的第一个思路就是找到规律,打表,将每个图进行计算存入数组。但是后来发现,数组的大小它装不下!!!
所以必须要转变思路!!!
我们必须要把每个图对应的纸牌数量存下来吗? 不是的,我们只要我们需要的即可,多余算出来的只是浪费了空间。我们可以在需要的时候,用一个函数直接当场算即可,时间复杂度为 O ( 1 ) ,看来是可行的。
那规律是什么呢?
我们可以将其看成三角形(第一个图,两个纸牌)和横着的纸牌组成。

第一个图 (h = 1): 第一层,一个三角形,没有横条,即:(1,0)
第二个图 (h = 2): 第一层,一个三角形,一个横条。第二层,两个三角形,没有横条。即:(3,1)
第三个图(h = 3): 第一层,一个三角形,一个横条。第二层,两个三角形,两个横条。第三层,三个三角形,没有横条。即:(6,3)
我们从中可以看到规律 (h指高度):
横条个数:1+2+3+...+(h - 1) = (1 + h - 1) * (h - 1) / 2 = h * (h - 1) / 2
三角形个数:1+2+3+...+h = (1 + h) * h / 2 * 2 = (1 + h) * h
最后的规律为: h * (h - 1) / 2 + (1 + h) * h
在二分的时候,我们就枚举高度,即h,判断mid的时候就是看其通过规律得到的最后的值是否大于当前的纸牌数量,我们的目标是找到第一个小于纸牌数量的数,每次二分完后,将当前纸牌数减去最大需要的纸牌数,以此反复,直到高度 < 2 为止,所以外面还需套一层while,每次进入最外层的while(k >= 2)时,这是可以搭成的金字塔的数量就可以+1,说明可以搭一个三角形。最后输出答案即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int t;
long long callnum(long long x){
return (1+x)*x + x*(x-1)/2;
}
long long my_ef(int k){
int ans = 0;
while(k >= 2){
ans++;
long long l = 1,r = k;
long long res = 2;
while(l <= r){
long long mid = (l + r) / 2;
if(callnum(mid) > k){
r = mid - 1;
}
else{
res = max(res,callnum(mid));
l = mid + 1;
}
}
k -= res;
}
return ans;
}
int main(){
scanf("%d",&t);
for(int i = 1;i <= t;i++){
int n;
scanf("%d",&n);
printf("%lld\n",my_ef(n));
}
return 0;
}
附:谁能帮我看看这道题(学校竞赛太变态了!!)
本文来自博客园,作者:XDFZ武斌,转载请注明原文链接:https://www.cnblogs.com/XDFZwb1523/p/16211590.html

浙公网安备 33010602011771号