记录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 的数字用大写字母
A、B、C、⋯ 表示。
注意:乘数与被乘数还有结果,均为要求的进制表现形式
思路
- 表示不同进制下数的组成,从0~Zy👉字符串
- 数位进制的转换
- 三角形的情况输出👉双重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++的鸿沟)
printf是C语言遗留函数,%s格式符要求传入 C风格字符串(即char*或const char*):c// C语言中 printf("%s", "hello"); // ✓ "hello" 类型是 const char[6],可隐式转 const char*但
std::string是C++类对象,其内存布局如下: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,无需转换,代码更安全简洁。*竞赛口诀:
printf配c_str(),cout直接上,string转换别忘光,安全第一不撞墙。
416

被折叠的 条评论
为什么被折叠?



