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

记录52

cpp 复制代码
#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循环

代码简析

cpp 复制代码
#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

cpp 复制代码
// 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* 指针 **:

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

内存示意图 :

cpp 复制代码
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)
cpp 复制代码
string s = "hello";
cout << s << endl;          // ✓ 无需转换,类型安全
// 速度:开 ios::sync_with_stdio(false) 后与printf相当
场景2:必须与printf混用
cpp 复制代码
// 如题目要求用printf输出,或代码已全用printf
printf("Name: %s, Score: %d\n", name.c_str(), score);  // 必须转换
场景3:格式化输出
cpp 复制代码
printf("ID: %06d, Name: %10s\n", id, name.c_str());  // 格式化width
// cout实现较繁琐:setw(10) << name

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

陷阱1:对临时string调用
cpp 复制代码
// ⚠️ 危险!临时string销毁后,c_str()指向无效内存
printf("%s", (string("temp") + "data").c_str());  // 可能打印乱码

// ✅ 正确:先构造string对象
string temp = string("temp") + "data";
printf("%s", temp.c_str());
陷阱2:多次调用顺序
cpp 复制代码
// ⚠️ 危险!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:忘记转换导致编译失败
cpp 复制代码
vector<string> names;
printf("%s", names[0]);  // ❌ 编译错误

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

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

原则:优先用cout,避免c_str()
cpp 复制代码
#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;
}
混用场景:减少转换次数
cpp 复制代码
// ❌ 多次转换
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转换别忘光,安全第一不撞墙

相关推荐
你好~每一天2 小时前
数据分析专员:当传统汽车销售融入AI智能,如何驱动业绩新增长
大数据·数据结构·人工智能·学习·数据分析·汽车·高性价比
添砖java‘’2 小时前
Linux线程控制全解析
linux·c++·线程
Zmm147258369_2 小时前
专业做PC耐力板的服务商
c++
再__努力1点2 小时前
【76】Haar特征的Adaboost级联人脸检测全解析及python实现
开发语言·图像处理·人工智能·python·算法·计算机视觉·人脸检测
溟洵2 小时前
【算法C++】链表(题目列表:两数相加、两两交换链表中的节点、重排链表、合并 K 个升序链表、K 个一组翻转链表7)
数据结构·c++·算法·链表
_OP_CHEN2 小时前
【C++数据结构进阶】玩转并查集:从原理到实战,C++ 实现与高频面试题全解析
数据结构·c++·算法
gugugu.2 小时前
算法:hot100---128. 最长连续序列
算法
天呐草莓2 小时前
支持向量机(SVM)
人工智能·python·算法·机器学习·支持向量机·数据挖掘·数据分析
zore_c2 小时前
【数据结构】队列——超详解!!!(包含队列的实现)
c语言·网络·数据结构·c++·笔记·算法·链表