# 卡片
# 题目:
小蓝有很多数字卡片,每张卡片上都必然刻有 0 ∼ 9 中的一个数字。 卡片可以用来拼凑数字,假设小蓝拥有刻有数字 1 和数字 2 的卡片各一张,那么他可以 利用这两张卡片拼凑出数字 1, 2, 12, 21 这 4 个正整数。现给定刻有数字 0, 1, . . . , 9 的卡片各 2021 张,小蓝将利用这些卡片从 1 开始连续拼凑 数字,请问他最大能拼到数字几(注意:每张卡片只能利用一次)?
# 思路:
把每个数字的个数用数组记录下来,然后枚举每个数看能不能组成并减掉使用过的数字。分析可以看出数字 1 最先消耗完,所以用 1 判断。
# 代码:
// | |
// Created by Doubeer on 2024/3/6. | |
// | |
#include <bits/stdc++.h> | |
using namespace std; | |
int cnt[10]; | |
bool check(int x){ //x 表示当前枚举的数 | |
while(x){ | |
int b = x % 10; // 获取十进制下的每个数位 | |
if(b == 1) { | |
if(cnt[1] == 0) return false;//1 最先消耗完 | |
cnt[1] -- ; | |
} | |
x /= 10; // 将十位变为个位 | |
} | |
return true; | |
} | |
signed main(){ | |
for(int i = 0 ; i <= 9 ; i ++) cnt[i] = 2021; | |
for(int i = 1 ; ; i ++){ | |
if(!check(i)) return cout << i - 1 << '\n' , 0; | |
} | |
return 0; | |
} |
# 回文日期
# 题目:
给定(输入)一个 8 位数的日期,请找出(输出)该日期之后的下一个回文日期以及下 一个 ABABBABA 型回文日期。 若给定的日期为 20200202,则会有下列结果。・下一个回文日期为 20211202。・下一个 ABABBABA 型回文日期为 21211212。
# 分析:
一个一个日期判断太慢,可以只枚举年份,然后把年份反转当作月和日组成新日期,判断这个新日期是否合法即可。
# 代码:
#include <bits/stdc++.h> | |
using namespace std; | |
// 月份的日期 | |
int date , month[13] = {-1 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31}; | |
string check(int date) { | |
string s = to_string(date) , t = to_string(date); // 将整型转换为字符串 | |
reverse(t.begin() , t.end()); // 翻转 | |
s += t; // 将 s 翻转后再与 s 拼接,拼接后的字符串一定会是个回文串 | |
int y = stoi(s.substr(0 , 4)), m = stoi(s.substr(4 , 2)), d = stoi(s.substr(6 , 2)); | |
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) month[2] = 29; | |
else month[2] = 28; | |
if (m < 1 || m > 12 || d < 1 || d > month[m]) return "-1"; | |
return s; | |
} | |
string check1(int date) { | |
string s = to_string(date) , t = to_string(date); // 将整型转换为字符串 | |
reverse(t.begin() , t.end()); // 翻转 | |
s += t; | |
if (s[0] == s[2] && s[0] == s[5] && s[0] == s[7] && s[1] == s[3] && s[1] == s[4] && s[1] == s[6]) | |
return s; | |
return "-1"; | |
} | |
int main() { | |
cin >> date; | |
string ans1 = ""; | |
for (int i = date / 10000; ; i++) { | |
// 没找到或者找到自身 | |
if (check(i) == "-1" || check(i) == to_string(date)) continue; | |
if (ans1 == "") ans1 = check(i); | |
if (check1(i) != "-1") return cout << ans1 << '\n' << check1(i) << '\n' , 0; | |
} | |
return 0; | |
} |
# 赢球票
# 题目:
给定 n 张卡片,卡片上分别写着数字 a1, a2, . . . , an。 现将这 n 张卡片围成一个圈。 我们可以从圈上任意一个位置开始顺时针数数:1, 2, 3 . . .。 若当前数到的数字和卡片上的数字相同,则将卡片取走,并从下一张卡片所在位置重新 数数:1, 2, 3 . . .。 问我们取走的卡片上的数字之和最大可以是多少?
# 分析:
用数组保存数据,pos 表示当前位置,pos++ 模拟转圈,pos=n 时,pos 重新赋值 1。
用数组 flag 来记录卡片拿走与否,如果卡片已经被拿走,则 pos++,否则标记
# 代码:
#include <bits/stdc++.h> | |
using namespace std; | |
const int N = 1e2 + 10; | |
int n, a[N], flag[N]; | |
int main() { | |
cin >> n; | |
for (int i = 0; i < n; i++) cin >> a[i]; | |
int ans; | |
for (int i = 0; i < n; i++) {// 枚举每个位置作起点 | |
for (int j = 1 ; j <= n ; j ++) flag[j] = 0; | |
//num 表示数的数的值,pos 表示当前位置,sum 表示以 i 为起点数数所能取走的卡片的和,cnt 表示拿走的卡片的数量 | |
int num = 1, pos = i, sum = 0, cnt = 0; | |
while (1) { | |
if (cnt == n || num > n) break; | |
if (flag[pos] == 1) {// 如果该卡片已被取走,则移动到下一个位置 | |
if (pos == n) pos = 1; | |
pos++; | |
continue; | |
} | |
// 数的数和当前位置卡片的值相同时取走该卡片(a [pos] 表示第 pos 张卡片的值) | |
if (num == a[pos]) { | |
sum + a[pos]; | |
cnt++; | |
num = 1; | |
flag[pos] = 1; | |
if (pos == n) pos = 1; | |
else pos++; | |
} else { | |
// 数的数和当前位置卡片的值不相同时 | |
num++; | |
if (pos == n) pos = 1; | |
else pos++; | |
} | |
} | |
// 模拟结束 | |
if (sum > ans) ans = sum; | |
} | |
cout << ans << '\n'; | |
return 0; | |
} |
# 即约分数
# 题目:
如果一个分数的分子和分母的最大公约数是 1,这个分数称为既约分数。 例如 3 4 , 1 8 , 7 1 ,都是既约分数。 请问,有多少个既约分数,分子和分母都是 1 到 2020 之间的整数(包括 1 和 2020 )?
# 分析
辗转相除法 gcd (i,j) 求 i 和 j 的最大公约数,枚举分母和分子,然后 gcd 判断最大公约数是不是等于 1
# 代码:
#include<bits/stdc++.h> | |
using namespace std; | |
signed main() | |
{ | |
int ans = 0; | |
for(int i = 1 ; i <= 2020 ; i ++){ | |
for(int j = 1 ; j <= 2020 ; j ++){ | |
if(_gcd(i , j) == 1) ans ++ ; | |
} | |
} | |
cout << ans << '\n'; | |
return 0; | |
}主函数结束 |
# 数的分解
# 题目:
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和 1001+1000+18 被视为同一种。
# 分析:
暴力复杂度 o(n^3), 想办法降低。用数组 flag 把数是否满足条件保存起来。三个加数 a,b,c,知道 a,b 则 c = 2019-a-b,且 a<b<c
# 代码:
#include <bits/stdc++.h> | |
using namespace std; | |
bool check(int x) { | |
while (x) { | |
if (x % 10 == 2 || x % 10 == 4) return false; | |
x /= 10; | |
} | |
return true; | |
} | |
bool flag[2020]; | |
int main() { | |
int ans = 0; | |
for(int i = 1 ; i <= 2019 ; i ++) if(check(i)) flag[i] = 1; // 在枚举前判断一个数是否包含 2 和 4,避免在枚举过程中判 | |
for(int i = 1 ; i <= 2019 ; i ++) | |
for(int j = i + 1 ; j < 2019 - i - j ; j ++) // i < j < 2019 - i - j | |
if(flag[i] && flag[j] && flag[2019 - i - j]) // 通过 flag 判断,复杂度 O (1) | |
ans ++; | |
cout << ans << '\n'; | |
return 0; |