记录61
#include<bits/stdc++.h>
using namespace std;
int main(){
string s,st="0123456789X";
int sum=0,t,cnt=0;
cin>>s;
int len=s.size();
for(int i=0;i<len-1;i++){
if(s[i]>='0'&&s[i]<='9'){
cnt++;
t=s[i]-'0';
sum+=t*cnt;
}
}
t=sum%11;
if(s[len-1]==st[t]) cout<<"Right";
else{
s[12]=st[t];
cout<<s;
}
return 0;
}
题目传送门
https://www.luogu.com.cn/problem/P1055
突破口
首位数字乘以 1 加上次位数字乘以 2 ……以此类推,用所得的结果 mod11,所得的余数即为识别码,如果余数为 10,则识别码为大写字母 X。例如 ISBN 号码
0-670-82162-4中的识别码 4 是这样得到的:对067082162这 9 个数字,从左至右,分别乘以 1,2,…,9 再求和,即 0×1+6×2+……+2×9=158,然后取 158mod11 的结果 4 作为识别码。你的任务是编写程序判断输入的 ISBN 号码中识别码是否正确,如果正确,则仅输出
Right;如果错误,则输出你认为是正确的 ISBN 号码。
思路
- 把字符串里面的数字取出来
- 将数字乘以它本事是第几个数字
- 取余后进行判断
代码简析
#include<bits/stdc++.h>
using namespace std;
int main(){
string s,st="0123456789X";
int sum=0,t,cnt=0;
cin>>s;
int len=s.size();
for(int i=0;i<len-1;i++){
if(s[i]>='0'&&s[i]<='9'){
cnt++;
t=s[i]-'0';
sum+=t*cnt;
}
}
t=sum%11;
if(s[len-1]==st[t]) cout<<"Right";
else{
s[12]=st[t];
cout<<s;
}
return 0;
}
string s;( ISBN 号码)
st="0123456789X"; 👉 取余11后的值
int sum=0(累加求和),t(字符串中取出的数字),cnt=0;(第几个数字)
for(int i=0;i<len-1;i++){} 👉 遍历字符串
if(s[i]>='0'&&s[i]<='9'){} 👉 找到数字进行处理
t=sum%11; 👉 得到识别码,对应着st字符串的下标
if(s[len-1]==st[t]) cout<<"Right"; 👉 相等时输出正确
else{s[12]=st[t];cout<<s;} 👉 不相等时,修改最后一位后输出
补充
CSP-J字符串操作技巧完全汇总
一、输入输出处理(竞赛第一步)
1.1 不同读取方式
// 方式1:读取单词(遇空格/换行停止) string s; cin >> s; // 输入"hello world",s="hello" // 方式2:读取整行(含空格) string line; getline(cin, line); // 输入"hello world",line="hello world" // ⚠️ 注意:若前面用过cin,需先cin.ignore()清空缓冲区 // 方式3:读取到字符数组(C风格) char str[1005]; scanf("%s", str); // 读取单词 gets(str); // ⚠️ 危险!读取整行,易溢出,禁用 fgets(str, 1005, stdin); // 安全读取整行,但保留'\n'1.2 处理空格与换行
// 需求:读取含空格的字符串 // 错误:cin >> s会截断 // 正确: getline(cin, line); // 读取多个数字字符串 while (cin >> s) { // 自动忽略空格和换行 // 处理s }
二、基本遍历与修改(高频操作)
2.1 三种遍历方式
string s = "abcdef"; // 方式1:下标遍历(最通用) for (int i = 0; i < s.size(); i++) { s[i] = toupper(s[i]); // 转大写 } // 方式2:范围for(简洁) for (char &c : s) { // &引用可修改 if (c == 'a') c = 'b'; } // 方式3:迭代器(少用) for (auto it = s.begin(); it != s.end(); ++it) { *it = 'x'; }2.2 修改字符
// 单点修改 s[0] = 'A'; // O(1) // 尾部增删 s.push_back('x'); // 尾部加,O(1) s.pop_back(); // 尾部删,O(1) // 中间插入(性能差,避免) s.insert(3, "abc"); // O(n),慎用 // 删除区间 s.erase(3, 3); // 从位置3删3个字符,O(n),慎用竞赛铁律:中间插入/删除少用,用
push_back/pop_back+重构
三、查找与匹配(CSP-J核心)
3.1 子串查找
string s = "hello world hello"; size_t pos = s.find("world"); // 返回首次位置,找不到返回npos if (pos != string::npos) { // 找到 cout << pos; // 输出6 } // 查找所有出现 size_t start = 0; while ((pos = s.find("hello", start)) != string::npos) { cout << pos << " "; start = pos + 1; // 从下一个位置继续找 }3.2 字符查找
// 找字符首次出现 pos = s.find('o'); // O(n) // 反向查找 pos = s.rfind('o'); // 从后往前找陷阱:返回
size_t类型,不是int,比较时用string::npos(值为-1)
四、截取与拼接(高频)
4.1 截取子串
string s = "hello world"; string sub1 = s.substr(6, 5); // 从位置6截取5个字符,"world" string sub2 = s.substr(6); // 从位置6到末尾,"world" // 应用场景:分离路径 string path = "/home/user/file.txt"; size_t pos = path.rfind('/'); // 从后找'/' string dir = path.substr(0, pos); // "/home/user" string file = path.substr(pos + 1); // "file.txt"4.2 拼接字符串
// 方式1:+=(推荐) string s = "a"; s += "b"; // s="ab" s += 'c'; // s="abc" // 方式2:append() s.append("def"); // s="abcdef" // 方式3:+(创建临时对象,性能稍差) string s2 = s + "xyz"; // s不变,s2="abcxyz" // 方式4:stringstream(复杂拼接) ostringstream oss; oss << "ID:" << id << ", Score:" << score; string result = oss.str();竞赛铁律:**循环内用
+=,不要用+**(避免创建临时对象)
五、类型转换(竞赛必背)
** 5.1 数字 → 字符串 **
// 方式1:to_string()(C++11,推荐) int x = 123; string s = to_string(x); // "123" ll y = 1234567890123LL; string s2 = to_string(y); // "1234567890123" // 方式2:sprintf()(C风格) char buf[20]; sprintf(buf, "%d", x); string s = buf; // 方式3:stringstream(兼容C++98) ostringstream oss; oss << x; string s = oss.str();5.2 字符串 → 数字
// 方式1:stoi/stoll()(C++11,但Dev-C++可能不支持) string s = "123"; int x = stoi(s); // 转int ll y = stoll(s); // 转long long // 方式2:atoi/atoll()(C风格,需c_str()) int x = atoi(s.c_str()); // 转int ll y = atoll(s.c_str()); // 转long long // 方式3:stringstream(最安全) stringstream ss(s); int x; ss >> x; // 成功返回1,失败返回0 // 方式4:手动实现(竞赛推荐) int strToInt(string s) { int ans = 0, sign = 1, i = 0; if (s[0] == '-') { sign = -1; i = 1; } for (; i < (int)s.size(); i++) ans = ans * 10 + (s[i] - '0'); return ans * sign; }竞赛铁律:比赛中禁用
stoi(),用atoi()或手写,避免编译失败
六、高级技巧(CSP-J压轴题)
6.1 前缀/后缀处理
// 前缀和 ll pre[N]; for (int i = 0; i < n; i++) pre[i+1] = pre[i] + (s[i] - '0'); // 前缀哈希(滚动哈希) unsigned long long h = 0, base = 131; for (char c : s) { h = h * base + c; } // 前缀函数(KMP的next数组) int nxt[N]; for (int i = 1, j = 0; i < n; i++) { while (j > 0 && s[i] != s[j]) j = nxt[j-1]; if (s[i] == s[j]) j++; nxt[i] = j; }6.2 双指针技巧
// 场景:找最长无重复子串 int cnt[256] = {0}, left = 0, ans = 0; for (int right = 0; right < n; right++) { cnt[s[right]]++; while (cnt[s[right]] > 1) { // 重复移动左指针 cnt[s[left]]--; left++; } ans = max(ans, right - left + 1); }6.3 滑动窗口
// 场景:找包含所有模式串的最短子串 unordered_map<char, int> need, window; int left = 0, right = 0, valid = 0; while (right < n) { char c = s[right]; window[c]++; if (need[c] == window[c]) valid++; while (valid == need.size()) { // 找到窗口,更新答案 if (right - left + 1 < minLen) { minLen = right - left + 1; start = left; } char d = s[left]; if (need[d] == window[d]) valid--; window[d]--; left++; } right++; }6.4 字符串反转
// 方式1:reverse算法 reverse(s.begin(), s.end()); // O(n) // 方式2:手动交换 for (int i = 0, j = s.size() - 1; i < j; i++, j--) { swap(s[i], s[j]); }
七、性能优化(防TLE)
7.1 避免低效操作
// ❌ 极低效:循环内频繁字符串拼接 string ans; for (int i = 0; i < 1e6; i++) { ans += char('a' + i % 26); // O(n²),1e12次操作 } // ✅ 高效:预先reserve空间 ans.reserve(1e6); // 预先分配内存 for (int i = 0; i < 1e6; i++) { ans.push_back('a' + i % 26); // O(n) } // ✅ 更高效:用char[]再转string char buf[1000005]; int len = 0; for (int i = 0; i < 1e6; i++) { buf[len++] = 'a' + i % 26; } string ans(buf, len);7.2 减少字符串拷贝
// ❌ 低效:传值 void func(string s) { ... } // 拷贝一次 // ✅ 高效:传引用 void func(const string& s) { ... } // 零拷贝
八、竞赛实战模板(背下来)
模板1:处理多行字符串
int n; cin >> n; cin.ignore(); // 跳过换行 for (int i = 0; i < n; i++) { string line; getline(cin, line); // 处理line }模板2:字符串分割
vector<string> split(const string& s, char delim) { vector<string> res; stringstream ss(s); string item; while (getline(ss, item, delim)) { res.push_back(item); } return res; } // 使用:vector<string> parts = split("a,b,c", ',');模板3:快速字符计数
int cnt[256] = {0}; for (char c : s) cnt[c]++; // 找最多字符 char maxChar = 0; for (int i = 0; i < 256; i++) { if (cnt[i] > cnt[maxChar]) maxChar = i; }
九、一句话总结
CSP-J字符串=输入用cin+getline,遍历用范围for,查找用find(),转换用to_string()和手写stoll,高级用双指针+前缀和,中间插入删除要避免,比赛混用printf记得c_str()。
2187

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



