纸牌金字塔

题目描述:

高度为1的纸牌金字塔是通过将两张纸牌彼此相对放置而构成的。 对于h > 1,通过将高度为h-1的卡片金字塔放置在底座上来构建高度为h的卡片金字塔。底座由高度为1的h金字塔和顶部为h-1的卡片组成。 例如,高度为1,2和3的纸牌金字塔如下所示
image
您从N张牌开始,然后建造最高的金字塔。 如果有剩余的纸牌,则可以使用剩余的纸牌建立最高的金字塔。 您重复此过程,直到不可能建造另一个金字塔。 最后,您将建造多少座金字塔?

输入:

第一行一个整数t表示数据组数(1≤t≤1000)

每组数据一行包括一个整数n表示纸牌的数量。(1≤n≤1e9)

输出:

每组数据一行表示答案

样例输入:

5
3
14
15
24
1

样例输出:

1
2
1
3
0

思路:

我的第一个思路就是找到规律,打表,将每个图进行计算存入数组。但是后来发现,数组的大小它装不下!!!

所以必须要转变思路!!!

我们必须要把每个图对应的纸牌数量存下来吗? 不是的,我们只要我们需要的即可,多余算出来的只是浪费了空间。我们可以在需要的时候,用一个函数直接当场算即可,时间复杂度为 O ( 1 ) ,看来是可行的。

那规律是什么呢?

我们可以将其看成三角形(第一个图,两个纸牌)和横着的纸牌组成。

image
第一个图 (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;
} 

附:谁能帮我看看这道题(学校竞赛太变态了!!)

题目:Mobile Severs

posted @ 2022-04-30 22:12  XDFZ武斌  阅读(621)  评论(0)    收藏  举报