Solution
T1 回文数
原题链接
简要思路
- 进位情况
当所有数位都为 \(9\) 的时候才会进位,此时输出形如1000001
的形式 - 不进位情况
- 如果 \(n\) 的前一半翻过来比后一半更大就直接把 \(n\) 的前一半翻过来贴在 \(n\) 的后面。
- 否则就把 \(n\) 的前一半 \(+1\) 翻过来贴在 \(n\) 的后面。
注意处理好 \(n\) 的位数为 奇数/偶数 的情况。
完整代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
char s[201],ans[201];
int i;
signed main(){
cin>>s;
int len=strlen(s)-1;
while(s[i++]=='9')
if(i==len+1){
s[0]='1';
len++;
for(;i>0;i--)
s[i]='0';
}
for(i=0;i<=len-i;i++)
ans[i]=ans[len-i]=ans[i];
if(strcmp(ans,s)<=0){
while(ans[--i]=='9');ans[i]=ans[len-i]=++ans[i];
for(i++;i<=len-i;i++)
ans[i]=ans[len-i]='0';
}
cout<<ans<<endl;
return 0;
}
T2 求和
原题链接
简要思路
枚举所有 “好数”,最后去重即可。
注意当考虑数位中含有 23512457898
的情况时,注意分讨:数位前面有几个多加的数,后面又有几个。
完整代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll power10[15], n, ans = 0;//power10[i] 代表 10^i
const ll QQ = 2351257898;
vector<ll> vec;
int main() {
power10[0] = 1;
for (int i = 1; i < 15; i++) {//预处理
power10[i] = power10[i - 1] * 10;
}
cin >> n;
for (int i = 1; i <= n / QQ; i++) {//先把倍数的情况加入 vector 中
vec.push_back(QQ * i);
}
//考虑当数位中有 2351257898 时的情况
for (int pos = 1; pos <= 5; pos++) {//第一层代表枚举数位前面有几个多加的数,后面有几个多加的数
for (int rest = 0; rest <= 9999; rest++) {//第二层枚举代表多加的数是啥
ll tmp = QQ * power10[pos - 1] + rest % power10[pos - 1] + rest / power10[pos - 1] * power10[pos + 9];//计算
if (tmp <= n)
vec.push_back(tmp);//如果合法才计入答案
}
}
sort(vec.begin(), vec.end());//排序
vec.erase(unique(vec.begin(), vec.end()), vec.end());//去重
for (auto x: vec) {//枚举 vector 中的每一个数
ans += x;
}
cout << ans << endl;
return 0;
}
T3 计算
原题链接
简要思路
前缀和 + 桶 + 差分。
完整代码
#include <bits/stdc++.h>
#define maxn 100010
#define ll long long
using namespace std;
int a[maxn], cnt[maxn], n, l, r;
ll ans[maxn], tag[maxn];
int main() {
cin >> n >> l >> r;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
ans[0] += l / a[i];
}
for (int i = 1; i <= n; i++) {
if (a[i] < maxn)
cnt[a[i]]++;
}
for (int i = 1; i < maxn; i++) {
/* pos = the minimum multiple of i that is greater than l */
int pos = (l / i + 1) * i;
while (pos <= r) {
tag[pos - l] += cnt[i];
pos += i;
}
}
for (int i = 1; i <= n; i++) {
if (a[i] < maxn)
continue;
/* pos = the minimum multiple of a[i] that is greater than l */
int pos = (l / a[i] + 1) * a[i];
while (pos <= r) {
tag[pos - l]++;
pos += a[i];
}
}
for (int i = 1; i <= r - l; i++) {
ans[i] = ans[i - 1] + tag[i];
}
for (int i = 0; i <= r - l; i++) {
cout << ans[i] << "\n "[i < r - l];
}
return 0;
}
T4 保 KDA
原题链接
简要思路
01 分数规划 + 背包
完整代码
咕咕。
讲课笔记
洛谷 P3908
原题链接
相关知识
位运算。
位运算符号:&
,|
,^
-
&
1&1=1 1&0=0 0&0=0 0&1=0
-
|
1|1=1 1|0=1 0|1=1 0|0=0
-
^
二进制的不进位加法。
1^1=0 1^0=1 0^1=1 0^0=0
两个相同的数字异或答案为 \(0\):\(a^a=0\)
简要思路
一个偶数异或下一个奇数的答案为 \(1\):\((2k) ^ (2k+1) = 1\)
- 当 \(n\) 是奇数时
如果 \((n-1)/2\) 为奇数,答案为 \(0\)。
偶数答案则为 \(1\)。 - 当 \(n\)
完整代码
洛谷 P4942
原题链接
题面
相关知识
如果一个数的数位之和为 \(3\) 的倍数,那么这个数就是 \(3\) 的倍数。
如果一个数的个数位上为 \(0\) 或 \(5\),那么这个数就是 \(5\) 的倍数。
如果一个数的千位及其以前的数位组成的数减去后三位数,得到的答案的绝对值为 \(7\) 或 \(11\) 或 \(13\) 的倍数,那么这个数就是 \(7\) 或 \(11\) 或 \(13\) 的倍数。
简要思路
完整代码
洛谷 P6267
原题链接
题面
相关知识
分解质因数
简要思路
完整代码
洛谷 P1029
原题链接
题面
相关知识
最大公约数和最小公倍数
- 辗转相除
- 指数(分解质因子),min-max
简要思路
完整代码
洛谷 P1072
原题链接
题面
相关知识
简要思路
-
模拟
-
PPT
完整代码
-
模拟做法
-
(PPT) 做法
洛谷 P3197
原题链接
题面
相关知识
组合数
- 例题 1
共有 \(n\) 个相同的小球,放置于 \(m\) 个不同个盒子中,保证每个盒子都非空的方案数。
\(C^{m-1}_{n-1}\)
- 例题 2
如果不要求非空,一开始就将每个盒子的初始值为 \(1\),最后减去 \(m\) 个小球就为 \(C^{m-1}_{n+m-1}\)。
上述为 插板法。
- 例题 3
不同小球,不同盒子,可以为空。
每个小球都可以放置在任何盒子里,答案为 \(m^n\)。
简要思路
完整代码
进阶
一号房间和 \(n\) 号房间连接,成为了环。