P8723 [蓝桥杯 2020 省 AB3] 乘法表

记录52

#include<bits/stdc++.h>
using namespace std;
string str="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
string f(int x,int y){
	int t;
	string s="";
	while(x){
		t=x%y;
		s=str[t]+s;
		x/=y;
	}
	return s;
}
int main(){
	int p;
	cin>>p;
	for(int i=1;i<=p-1;i++){
		for(int j=1;j<=i;j++){
			// string a=f(i,p);
   //    string b=f(j,p);
   //    string c=f(i*j,p);
   //    printf("%s*%s=%s ",a.c_str(),b.c_str(),c.c_str());
			cout<<f(i,p)<<"*"<<f(j,p)<<"="<<f(i*j,p)<<" ";
		}
		cout<<endl;
	} 
	return 0;
} 

题目传送门https://www.luogu.com.cn/problem/P8723


突破点

输出 P 进制下的乘法表。P 进制中大于等于 10 的数字用大写字母 ABC、⋯ 表示。

注意:乘数与被乘数还有结果,均为要求的进制表现形式


思路

  1. 表示不同进制下数的组成,从0~Zy👉字符串
  2. 数位进制的转换
  3. 三角形的情况输出👉双重for循环

代码简析

#include<bits/stdc++.h>
using namespace std;
string str="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
string f(int x,int y){
	int t;
	string s="";
	while(x){
		t=x%y;
		s=str[t]+s;
		x/=y;
	}
	return s;
}
int main(){
	int p;
	cin>>p;
	for(int i=1;i<=p-1;i++){
		for(int j=1;j<=i;j++){
			// string a=f(i,p);
   //    string b=f(j,p);
   //    string c=f(i*j,p);
   //    printf("%s*%s=%s ",a.c_str(),b.c_str(),c.c_str());
			cout<<f(i,p)<<"*"<<f(j,p)<<"="<<f(i*j,p)<<" ";
		}
		cout<<endl;
	} 
	return 0;
} 

string str 👉 存所有进制的表现情况,下标对应真实数值,存放为表达形式

string f(int x,int y){} 👉 函数处理这个数字在进制下的表达,最后返回字符串类型的转换情况

while(x){} 👉数位分离,把分离出的数进行进制转换

s=str[t]+s; 👉 注意后分离出的为高位 

例:1234

分离的情况为 4,3,2,1  位数高的最后分离出来

所以最后分离出的是高位,应该写再前面

for(int i=1;i<=p-1;i++){} 👉 外层for循环决定有几行,比当前进制少一位的行数

for(int j=1;j<=i;j++){} 👉 内层for循环决定有几列,j<=i 三角打印 

注意:如果用printf打印字符串,需要用c_str()函数


补充

printf打印string必须用c_str()的原理与竞赛实践


1. 根本原因:类型不匹配(C与C++的鸿沟)

printfC语言遗留函数,%s 格式符要求传入 C风格字符串(char*const char*):c

// C语言中
printf("%s", "hello");  // ✓ "hello" 类型是 const char[6],可隐式转 const char*

std::stringC++类对象,其内存布局如下:

string对象 ≈ { size_t size; size_t capacity; char* data_ptr }

不是指针!直接传 string 对象,printf 无法识别,编译器会报错。


2. c_str() 的作用:提取C字符串指针

c_str() 返回 string 内部字符数组的** const char* 指针 **:

string s = "world";
const char* p = s.c_str();  // p指向 "world\0"
printf("%s", s.c_str());    // ✓ 正确:类型匹配

内存示意图 :

string对象:  [ size=5 | capacity=15 | data_ptr=0x1234 ]
              ↓ c_str()
内存0x1234:  'w' 'o' 'r' 'l' 'd' '\0'  // C字符串格式

3. 错误示例 vs 正确示例

代码结果原因
printf("%s", s);编译错误类型不匹配,string 不是 char*
printf("%s", &s);打印乱码打印的是 string 对象的地址,不是字符串内容
printf("%s", s.data());可能无\0结尾data() 不保证以 \0 结尾,printf 会越界读取
printf("%s", s.c_str());✓ 正确返回带 \0 的C字符串,安全

4. CSP竞赛中的使用场景与推荐

场景1:纯C++代码(推荐用cout)

string s = "hello";
cout << s << endl;          // ✓ 无需转换,类型安全
// 速度:开 ios::sync_with_stdio(false) 后与printf相当
场景2:必须与printf混用

// 如题目要求用printf输出,或代码已全用printf
printf("Name: %s, Score: %d\n", name.c_str(), score);  // 必须转换
场景3:格式化输出

printf("ID: %06d, Name: %10s\n", id, name.c_str());  // 格式化width
// cout实现较繁琐:setw(10) << name

5. 竞赛中的常见陷阱(致命)

陷阱1:对临时string调用

// ⚠️ 危险!临时string销毁后,c_str()指向无效内存
printf("%s", (string("temp") + "data").c_str());  // 可能打印乱码

// ✅ 正确:先构造string对象
string temp = string("temp") + "data";
printf("%s", temp.c_str());
陷阱2:多次调用顺序

// ⚠️ 危险!substr()生成临时对象,第二个c_str()可能失效
printf("%s %s\n", s.c_str(), s.substr(1).c_str());

// ✅ 正确:分开写
string sub = s.substr(1);
printf("%s %s\n", s.c_str(), sub.c_str());
陷阱3:忘记转换导致编译失败

vector<string> names;
printf("%s", names[0]);  // ❌ 编译错误

// ✅ 正确
printf("%s", names[0].c_str());

6. CSP竞赛最佳实践(金牌选手模板)

原则:优先用cout,避免c_str()

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);  // 关闭C++与C的IO同步
    cin.tie(nullptr);              // 解除cin与cout绑定
    
    string s;
    cin >> s;
    
    // 方式1:cout(推荐,无需转换)
    cout << s << endl;  // ✓ 类型安全,无溢出风险
    
    // 方式2:printf(仅当必须用格式化时)
    printf("Result: %s\n", s.c_str());  // ✓ 需转换,但安全
    
    return 0;
}
混用场景:减少转换次数

// ❌ 多次转换
printf("%s", s1.c_str());
printf("%s", s2.c_str());

// ✅ 一次性构造C字符串(罕见,不推荐)
char buf[100];
sprintf(buf, "%s %s", s1.c_str(), s2.c_str());
printf("%s", buf);

7. 一句话总结

printf 是C函数,只认char*,不认string,所以必须用.c_str()转换;但CSP竞赛中更推荐用cout,自动处理string,无需转换,代码更安全简洁。 

*竞赛口诀: printfc_str()cout直接上,string转换别忘光,安全第一不撞墙

### 关于2020蓝桥杯AB组第一题解码问题 对于2020蓝桥杯AB组的第一题——解码问题,虽然提供的参考资料中并未直接提及该具体题目[^1],但可以根据过往此类竞赛题目的特点以及编码与解码的基础理论来构建可能的解析框架。 #### 题目概述 通常情况下,“解码”类题目会给出一段经过特定规则加密后的字符串或者是数字序列,并要求参赛者依据给定或推断出的规律将其还原为原始的信息形式。这类题目往往涉及到字符映射、位运算、模式识别等计算机科学基础知识的应用。 #### 解析思路 针对解码类型的题目,解决方法一般遵循以下几个方面: - **理解输入输出格式**:仔细阅读题目描述中的例子部分,明确知道什么样的数据作为输入将会得到怎样的预期输出。 - **寻找转换规则**:通过观察样例之间的关系尝试找出隐藏在其背后的逻辑或者数学表达式。这一步骤可能是基于简单的算术操作(加减乘除)、ASCII码表上的位置变换或者其他更复杂的函数映射。 - **编写验证程序**:一旦确定了解密算法,则应该立即实现相应的代码并利用测试用例来进行调试直至能够正确处理所有情况为止。 考虑到本题属于级比赛初级阶段的一部分,难度相对适中,因此建议采用较为直观的方法去探索潜在的解密机制,比如逐字对比差异、考虑常见密码学基础概念如凯撒移位等方式入手。 ```python def decode_string(encoded_str): # 假设这里实现了具体的解码逻辑 decoded_result = "" for char in encoded_str: # 这里只是一个示意性的简单替换过程, # 实际上应根据实际题目条件调整此处的具体实现细节 new_char = chr(ord(char) - 3) # 如果是简单的字母偏移加密方式 decoded_result += new_char return decoded_result ``` 这段伪代码展示了如何创建一个基本的解码器模型;当然,在面对真实的考题时,需要根据具体情况修改内部的操作流程以适应不同的加密策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值