【题意】#80 A. Blackjack

本博客探讨了在BlackJack游戏中,已知玩家手中的第一张牌为黑桃Q的情况下,如何通过数学方法计算获得特定分数所需的第二张牌数量。通过理解游戏规则和牌的点数分配,读者可以掌握解决类似概率问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. Blackjack
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

One rainy gloomy evening when all modules hid in the nearby cafes to drink hot energetic cocktails, the Hexadecimal virus decided to fly over the Mainframe to look for a Great Idea. And she has found one!

Why not make her own Codeforces, with blackjack and other really cool stuff? Many people will surely be willing to visit this splendid shrine of high culture.

In Mainframe a standard pack of 52 cards is used to play blackjack. The pack contains cards of 13 values: 23456,78910, jacks, queens, kings and aces. Each value also exists in one of four suits: hearts, diamonds, clubs and spades. Also, each card earns some value in points assigned to it: cards with value from two to ten earn from 2 to 10points, correspondingly. An ace can either earn 1 or 11, whatever the player wishes. The picture cards (king, queen and jack) earn 10 points. The number of points a card earns does not depend on the suit. The rules of the game are very simple. The player gets two cards, if the sum of points of those cards equals n, then the player wins, otherwise the player loses.

The player has already got the first card, it's the queen of spades. To evaluate chances for victory, you should determine how many ways there are to get the second card so that the sum of points exactly equals n.

Input

The only line contains n (1 ≤ n ≤ 25) — the required sum of points.

Output

Print the numbers of ways to get the second card in the required way if the first card is the queen of spades.

Sample test(s)
input
12
output
4
input
20
output
15
input
10
output
0
Note

In the first sample only four two's of different suits can earn the required sum of points.

In the second sample we can use all tens, jacks, queens and kings; overall it's 15 cards, as the queen of spades (as any other card) is only present once in the pack of cards and it's already in use.

In the third sample there is no card, that would add a zero to the current ten points.


读懂题意即可的一道题。

有52张牌,分为四种花色,JQK和10一样都算10分,A可以当1分可以当11分,现在已经有一张黑桃Q了(10分),给出一个数字n,问再抽一张牌,他们的和为n的抽法有多少中种。

那么我们来等价一下题意:从A到K四种花色各一张,黑桃Q除外,A可以当1或者11,JQK为10,问值为 n-10 的牌有多少张。

牌的点数都大于等于1,所以如果n-10<=0,答案为0

反之,看有多少种了呗~记住黑桃Q用掉了所以如果需要10的话记得减一~

Code:

#include <cstdio>
#include <string>
#include <cstring> 
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
// http://codeforces.com/contest/104
// Black Jack
int ans[26]={0};

int main()
{
	int n;	cin>>n;
	for(int i=11;i<20;i++)ans[i]=4;
	ans[20]=15;	ans[21]=4;
	cout<<ans[n];
	return 0;
} 





<think>根据题目描述,我们需要生成一个n阶的一维分形图。分形图的生成规则如下: - 0阶分形图是一个字符&#39;#&#39; - n阶分形图由三部分组成: 1. 前3^(n-1)个字符是n-1阶分形图 2. 中间3^(n-1)个字符都是&#39;.&#39; 3. 后3^(n-1)个字符是n-1阶分形图 因此,整个分形图的长度是3^n。 我们可以使用递归或者迭代的方法来生成这个字符串。 由于n可能达到10左右(因为3^10=59049,而3^11=177147,在字符串长度允许范围内,但题目要求256MiB内存,所以n最大可能到12左右,因为3^12=531441,字符串长度约为50多万,可以接受),所以我们可以使用递归。 但是递归深度为n,而n不会太大,所以递归是可行的。然而,递归可能会导致重复计算,我们可以使用记忆化或者动态规划(自底向上)来避免重复计算。 这里我们采用自底向上的迭代方法,从0阶开始构建到n阶。 步骤: 1. 初始化一个字符串s0为"#",表示0阶分形图。 2. 对于k从1到n,构建k阶分形图:s_k = s_{k-1} + 中间3^(k-1)个&#39;.&#39; + s_{k-1} 但是注意:中间部分应该是3^(k-1)个&#39;.&#39;,而s_{k-1}的长度是3^(k-1),所以整个字符串长度为3^k。 但是注意:题目要求输出整个分形图,没有换行,就是一个长度为3^n的字符串。 例如: n=0: "#" n=1: 由三部分,每部分3^0=1个字符:前一部分是0阶分形图"#",中间部分1个&#39;.&#39;,后一部分0阶分形图"#",所以是"#.#" n=2: 由三部分,每部分3^1=3个字符:前一部分是1阶分形图"#.#",中间3个&#39;.&#39;,后一部分1阶分形图"#.#",所以是"#.#...#.#" 但是注意:中间部分应该是3个&#39;.&#39;,所以整个字符串是"#.#...###"吗?不对,应该是: 前3个字符: "#.#" 中间3个字符: "..." 后3个字符: "#.#" 所以合起来是"#.#...#.#" n=3: 每部分长度为3^2=9,所以整个字符串长度为27。 前9个字符:n=2阶分形图("#.#..."#.#")-> 这里注意n=2阶分形图是"#.#..."#.#"吗?不对,n=2阶分形图是"#.#...#.#"(长度为9),所以: 前9个: "#.#...#.#" 中间9个:9个&#39;.&#39;,即"........."(9个点) 后9个: "#.#...#.#" 所以整个字符串是:"#.#...#.#......... #.#...#.#"(中间9个点,前后相同) 但是注意:题目要求中间是3^(n-1)个点,所以n=3时中间是3^2=9个点。 因此,我们可以用迭代: 初始化:string fractal = "#"; 然后从1到n循环,每次新的fractal = 旧的fractal + 长度为(len(旧的fractal))的&#39;.&#39;字符串 + 旧的fractal 注意:在k阶时,字符串长度是3^k,而中间部分长度也是3^(k-1)(即旧字符串的长度),所以中间部分用3^(k-1)个&#39;.&#39;填充。 但是我们可以这样: for k in range(1, n+1): fractal = fractal + (&#39;.&#39; * (len(fractal))) + fractal 这样对吗? 在k=1时:fractal初始为"#",然后新fractal = "#" + &#39;.&#39;*1 + "#" -> "#.#",正确。 k=2时:fractal = "#.#" + &#39;.&#39;*3 + "#.#" -> "#.#...###"吗?不对,应该是"#.#...#.#",因为中间是3个点,而后面是"#.#",所以正确。 所以迭代公式为:fractal = fractal + string(3^(k-1), &#39;.&#39;) + fractal 但是注意:3^(k-1)就是当前阶的旧字符串长度(因为旧字符串是k-1阶,长度为3^(k-1))。 所以我们可以用一个字符串s,初始为"#" 然后循环k从1到n,每次s = s + string( s.length(), &#39;.&#39; ) + s 但是这样中间部分就是s.length()个点,而s.length()就是3^(k-1)。 因此,代码可以这样写: #include <iostream> #include <string> #include <cmath> using namespace std; int main() { int n; cin >> n; string fractal = "#"; // 如果n=0,直接输出"#" // 迭代构建:从1阶到n阶 for (int i = 1; i <= n; i++) { // 当前中间部分的长度是当前fractal的长度,即3^(i-1) string middle(fractal.size(), &#39;.&#39;); fractal = fractal + middle + fractal; } cout << fractal << endl; return 0; } 但是注意:题目要求输入n,输出n阶分形图。 我们测试一下: n=0: 输出"#" n=1: 输出"#.#" n=2: 输出"#.#...#.#" n=3: 输出"#.#...#.#......... #.#...#.#"(中间9个点,前后都是"#.#...#.#") 但是注意:n=3时,整个字符串长度是27,中间9个点,所以是: "#.#...#.#" + "........." + "#.#...#.#" -> 长度为9+9+9=27。 所以这个程序是正确的。 但是,当n=0时,我们的循环不会执行,所以fractal初始为"#",直接输出,正确。 注意:题目要求256MiB内存,n最大可能是多少?3^n,当n=20时,3^20≈3.48e9,超过了256MB(256MB大约可以存2.68e8个字符,因为1字符1字节,256MB=256*1024*1024≈2.68e8),所以n最大只能到18左右(3^18=387420489,约387MB,超过256MB),所以题目应该不会给那么大的n。但是题目没有说明n的范围,我们假设n在0到12之间(因为3^12=531441,在可接受范围)。 但是题目要求256MiB,所以n最大可能是18?但387MB>256MB,所以n最大可能是17(3^17=129140163,约129MB),在256MB内。 所以我们的程序需要能够处理n最大17的情况。使用字符串拼接,内存占用是3^n,所以当n=17时,需要129MB内存,可以接受。 但是,在迭代过程中,我们每次拼接都会创建一个新的字符串,而旧字符串会被复制两次,所以内存占用是递增的:每次迭代,字符串长度变为原来的3倍,所以总的内存占用是3^n,而中间过程会产生一些临时字符串,但总的内存占用大约是3^n+3^(n-1)+...+1,这是一个等比数列,和约为(3^(n+1)-1)/2,所以当n=17时,总内存占用大约是(3^18-1)/2≈5.8e8字节(580MB),超过了256MB。 因此,我们需要优化内存:我们不需要保存中间过程的所有字符串,只需要在最后生成整个字符串。但是迭代过程中,我们只保留当前的字符串,所以实际上每次迭代,我们只需要分配当前字符串长度的3倍的空间,然后释放旧字符串。但是C++的string在赋值时是复制,所以每次迭代都会复制两份旧字符串,然后拼接成新的,所以旧字符串会被销毁,因此整个过程中,我们只保留当前字符串,所以总内存占用就是当前字符串的长度(3^n)加上新字符串分配时的临时开销(可能会多复制一次,但总体是O(3^n))。 所以当n=17时,我们只需要129140163字节(约129MB)来存储最终字符串,而迭代过程中,最后一次分配需要约129MB,同时上一次的字符串需要43MB,再上一次需要14MB,等等,所以总的内存占用大约为129+43+14+4.7+1.5+0.5+...≈193MB,小于256MB。所以可以接受。 因此,我们使用迭代方法。 但是,如果n很大,比如n=18,那么最终字符串长度是387420489字节(约387MB),超过了256MB,所以程序可能内存不足。但题目没有给出n的范围,我们只能假设输入n在合理范围内(0<=n<=17)。 所以代码实现如下: 注意:如果n=0,直接输出"#",否则循环n次。 但是,我们也可以使用递归,但是递归深度为n,而n最大17,递归不会太深,但是递归可能导致函数调用栈深度为17,可以接受。但迭代更简单。 所以我们就用迭代。 代码: #include <iostream> #include <string> using namespace std; int main() { int n; cin >> n; string s = "#"; // 迭代n次,从1阶到n阶 for (int i = 1; i <= n; ++i) { s = s + string(s.size(), &#39;.&#39;) + s; } cout << s << endl; return 0; } 但是,我们测试一下: n=0: 输入0,循环0次,输出"#",正确。 n=1: 输出"#.#",正确。 n=2: 输出"#.#...#.#",正确。 所以这个程序是符合题意的。 注意:题目要求输出分形图,没有换行,就是一个字符串。 提交代码时,注意不要输出多余内容。 但是,当n=0时,输出"#",n=1时输出"#.#",题目定义是符合的。 因此,我们按照这个代码提交。 但是,我们考虑一下性能:当n=17时,字符串长度是3^17=129140163,大约1.3e8个字符,在C++中,使用string的拼接,在每次迭代中,我们都要创建一个新的字符串,长度为原来的3倍,而复制旧字符串两次(一次是s本身,一次是s本身,中间是点字符串)。所以第i次迭代,字符串长度为3^i,那么复制操作需要复制2*3^(i-1)个字符(因为旧字符串长度为3^(i-1),然后新字符串长度为3*3^(i-1)=3^i,其中需要复制旧字符串两次(每个长度为3^(i-1))和中间点字符串(长度为3^(i-1))。所以第i次迭代的复制操作次数为3^(i-1)*2 + 3^(i-1) = 3*3^(i-1)=3^i。所以总复制次数为3^1+3^2+...+3^n,这是一个等比数列,和为(3*(3^n-1))/2。当n=17时,总复制次数约为(3^18-3)/2≈(387420486)/2≈193710243,约1.9e8次复制,在1000ms内,C++应该可以完成(现代计算机每秒可以处理1e8次操作左右,所以0.2秒左右)。 因此,我们可以接受。 但是,我们可以优化:在每次迭代中,避免使用临时字符串拼接,而是预先分配空间。我们可以这样: string new_s; new_s.reserve(s.size() * 3); // 预分配空间 new_s = s; new_s.append(s.size(), &#39;.&#39;); // 添加s.size()个点 new_s.append(s); // 再添加s 这样,我们避免多次重新分配内存和复制。但是,在循环中,我们每次迭代都会重新分配,所以总的时间复杂度不变,但常数更小。 所以我们可以这样写: #include <iostream> #include <string> using namespace std; int main() { int n; cin >> n; string s = "#"; for (int i = 1; i <= n; ++i) { string t = s; // 第一部分 t.append(s.size(), &#39;.&#39;); // 添加中间部分 t.append(s); // 添加第三部分 s = t; } cout << s << endl; return 0; } 这样写更清晰,而且预分配由string的append自动处理(内部会预分配足够空间,避免多次重新分配)。 我们测试一下,结果相同。 所以我们可以用这个版本。 但是,我们也可以使用reserve来减少重新分配的次数: #include <iostream> #include <string> using namespace std; int main() { int n; cin >> n; string s = "#"; for (int i = 1; i <= n; ++i) { string t; t.reserve(s.size() * 3); // 预分配3倍空间 t = s; // 第一部分 t += string(s.size(), &#39;.&#39;); // 中间部分 t += s; // 第三部分 s = t; } cout << s << endl; return 0; } 这样效率更高。 但是,当n=0时,循环不执行,所以直接输出"#"。 我们选择这个版本。 但是,注意:在n=0时,我们不需要循环,所以不会进入循环,所以没问题。 现在,我们提交这个代码。 注意:题目要求1000ms,256MiB,所以n最大17,我们的程序可以满足。 因此,最终代码如下:</think>### 一维分形图的C语言实现 根据题目描述,一维分形图的生成规则如下: - 0阶分形图:单个字符 `#` - n阶分形图:由三部分组成 - 前 $3^{n-1}$ 个字符:$n-1$ 阶分形图 - 中间 $3^{n-1}$ 个字符:全部为 `.` - 后 $3^{n-1}$ 个字符:$n-1$ 阶分形图 #### 迭代法实现 使用迭代方法逐步构建分形图字符串,避免递归深度过大: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int n; scanf("%d", &n); // 计算总长度 = 3^n int len = 1; for (int i = 0; i < n; i++) len *= 3; // 分配内存 char *fractal = (char*)malloc(len + 1); fractal[0] = &#39;#&#39;; // 0阶分形图 // 迭代构建 for (int k = 1; k <= n; k++) { int seg_len = 1; for (int i = 0; i < k - 1; i++) seg_len *= 3; // 计算段长度 = 3^{k-1} // 复制前半部分 for (int i = seg_len - 1; i >= 0; i--) { fractal[2 * seg_len + i] = fractal[i]; // 后半部分 fractal[seg_len + i] = &#39;.&#39;; // 中间部分 fractal[i] = fractal[i]; // 前半部分(不变) } } fractal[len] = &#39;\0&#39;; // 字符串结束符 printf("%s\n", fractal); free(fractal); return 0; } ``` #### 递归法实现 使用递归方法直接生成分形图: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> void generate_fractal(char *arr, int start, int len, int n) { if (n == 0) { arr[start] = &#39;#&#39;; return; } int seg_len = len / 3; // 生成前半部分 generate_fractal(arr, start, seg_len, n - 1); // 生成中间部分 for (int i = start + seg_len; i < start + 2 * seg_len; i++) { arr[i] = &#39;.&#39;; } // 生成后半部分 generate_fractal(arr, start + 2 * seg_len, seg_len, n - 1); } int main() { int n; scanf("%d", &n); int len = (int)pow(3, n); // 总长度 = 3^n char *fractal = (char*)malloc(len + 1); generate_fractal(fractal, 0, len, n); fractal[len] = &#39;\0&#39;; printf("%s\n", fractal); free(fractal); return 0; } ``` ### 算法说明 1. **时间复杂度**:$O(3^n)$,需要生成 $3^n$ 个字符 2. **空间复杂度**:$O(3^n)$,需要存储整个分形字符串 3. **核心逻辑**: - 迭代法:通过三重循环逐步构建分形图 - 递归法:通过分治策略将问题分解为三个子问题 ### 示例输出 - `n=0`:`#` - `n=1`:`#.#` - `n=2`:`#.#...#.#` - `n=3`:`#.#...#.#......... #.#...#.#`(中间9个点) ### 性能优化建议 1. 对于 $n > 15$ 的情况,使用迭代法避免栈溢出 2. 预先计算段长度减少重复计算 3. 使用动态规划存储中间结果(适用于多次生成不同阶分形图) ### 分形几何的应用 分形在计算机图形学中用于生成自然景观、纹理合成和艺术设计[^1]。一维分形是理解分形几何的基础,其自相似性在信号处理和数据结构中也有应用[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糖果天王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值