文章目录
-
-
- [1 幸运数](#1 幸运数)
- [2 有奖问答](#2 有奖问答)
- [3 平方差](#3 平方差)
- [4 更小的数](#4 更小的数)
- [5 颜色平衡树](#5 颜色平衡树)
- [6 买瓜](#6 买瓜)
- [7 异或和之和](#7 异或和之和)
- [8 网络稳定性](#8 网络稳定性)
- [9 像素放置](#9 像素放置)
- [10 翻转硬币](#10 翻转硬币)
-
注 :只为拿分 部分优化思路没有更新
1 幸运数
题目描述:
小蓝认为如果一个数含有偶数个数位,并且前面一半的数位之和等于后面一半的数位之和,则这个数是他的幸运数字。例如 2314 是一个幸运数字, 因为它有 44 个数位, 并且 2+3=1+4 。现在请你帮他计算从 1 至 100000000 之间共有多少个不同的幸运数字。
比较简单,直接附上我的暴力题解:
答案:4430091
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
string to_str(int x) {
string res;
while(x) {
res = res + (char)(x % 10 + '0');
// cout<<res<<endl;
x /= 10;
}
reverse(res.begin(), res.end());
return res;
}
int main() {
int ans = 0;
for(int i = 10; i <= 100000000; i++) {
string str = to_str(i);
// cout<<str;
int len = str.size();
bool flag = true;
int left = 0, right = 0;
if(len % 2 == 0) {
for(int j = 0; j < len / 2; j++) {
left += (int)str[j];
right +=(int)str[len-j-1];
}
if(left==right) ans++;
}
}
cout << ans;
return 0;
}
2 有奖问答
题目描述:
小蓝正在参与一个现场问答的节目。活动中一共有 30 道题目, 每题只有答对和答错两种情况, 每答对一题得 10 分,答错一题分数归零。
小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要100 分, 所以到达 100 分时小蓝会直接停止答题。请注意小蓝也可能在不到 100 分时停止答题。
已知小蓝最终实际获得了 70 分对应的奖项, 请问小蓝所有可能的答题情况有多少种?
重点:
答错一题,分数全部归零,一开始看错题了,直接用的组合数+循环。。。
答案:8335366
代码:
附上dfs暴力求解:
cpp
#include <bits/stdc++.h>
using namespace std;
int ans = 0;
void dfs(int score, int n) {
//答题情况+1
if(score == 70) ans += 1;
//答完所有的题或达到100分 停止递归
if(n == 30 || score == 100) return;
dfs(score + 10, n + 1);
//答错score归零
dfs(0, n + 1);
}
int main(){
dfs(0,0);
cout<<ans;
return 0;
}
3 平方差
题目描述:
输入两个整数,输出 A 2 − B 2 的值 输入两个整数,输出A^2-B^2的值 输入两个整数,输出A2−B2的值
貌似真题不是这个,为什么官网给的上面这道题。。。
给定 L , R ,问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y , z 使得 x 2 = y 2 − z 2 给定 L,R,问 L≤x≤R 中有多少个数 x 满足存在整数 y,z 使得 x^2=y^2−z^2 给定L,R,问L≤x≤R中有多少个数x满足存在整数y,z使得x2=y2−z2
我们按下面这道题来
思路:数学+找规律
发现x 只要满足是奇数或者4的倍数就是一种答案,因为x的组合形式只能是奇×奇 或者 偶×偶 两个偶数相乘,结果一定是4的倍数。
- x/2上取整可以获得[1,x]奇数个数: ⌈9 / 2⌉ = 5(1,3,5,7,9为[1,x]的奇数)
- x/4下取整可以获得[1,x]4的倍数的个数⌊5 / 4⌋ = 1(只有4一个为4的倍数)
- 再加一个前缀和思想求区间内满足的个数
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
int calc(int x) {
return (x + 1) / 2 + x / 4;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int L, R;
cin >> L >> R;
cout << calc(R) - calc(L - 1) << endl;
return 0;
}
不是我说,这谁能在考场上做出这么大的假设并证明。。。
4 更小的数
题目描述:

小蓝想要将选出的子串进行反转后再放入原位置处得到的新的数字 numnew 满足条件 numnew<num,请你帮他计算下一共有多少种不同的子串选择方案,只要两个子串在 num 中的位置不完全相同我们就视作是不同的方案。
就是一个双指针,不断判断区间左端点和右端点的数字大小即可,附上我的题解:
代码:
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
using ll = long long;
bool is_smaller(int l, int r, const vector<char>& num) {
while (l < r && num[l] == num[r]) {
l++;
r--;
}
return num[l] > num[r];
}
int main() {
string input;
getline(cin, input);
vector<char> num;
for (char c : input) {
if (c != ' ') {
num.push_back(c);
}
}
ll ans = 0;
for (int i = 0; i < num.size(); i++) {
for (int j = i; j < num.size(); j++) {
if (is_smaller(i, j, num)) {
ans++;
}
}
}
cout << ans;
return 0;
}
5 颜色平衡树
题目描述:
给定一棵树,结点由 1 至 n 编号,其中结点 1 是树根。树的每个点有一个颜色 Ci。
如果一棵树中存在的每种颜色的结点个数都相同,则我们称它是一棵颜色平衡树。求出这棵树中有多少个子树是颜色平衡树。
思路:启发式合并
颜色数量最小=颜色数量最大,说明是颜色平衡树
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 8;
//vector<pair<int,int>> g[N];
//int col[200000];
map<int, int>col[N], num[N];
vector<int> g[N];
int ans;
void dfs(int x, int fa) {
//递归处理其所有子节点y
for(auto & y : g[x]) {
dfs(y, x);
//比较x和y的col大小,总是将小的合并到大的中
if(col[x].size() < col[y].size()) {
swap(col[x], col[y]);
swap(num[x], num[y]);
}
//遍历子节点y的颜色统计
for(auto it : col[y]) {
int y_col = it.first, y_num = it.second;
//如果颜色在x中已存在:合并数量,并更新num统计
if(col[x].count(y_col)) {
int x_num = col[x][y_col];
num[x][x_num]--;
if(num[x][x_num] == 0) num[x].erase(x_num);
num[x][x_num + y_num]++;
}
//如果颜色在x中不存在:直接添加
else num[x][y_num]++;
col[x][y_col] += y_num;
}
//清空子节点y的统计信息(释放内存)
map<int, int>tmp1, tmp2;
col[y].swap(tmp1);
num[y].swap(tmp2);
}
//x的子树中所有颜色出现的次数都相同
if(num[x].size() == 1) ans++;
}
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
int c, fa;
cin >> c >> fa;
//1号节点没有father 即fa=0
g[fa].push_back(i);
col[i][c]++;//i节点 颜色为c的数量
num[i][1]++; //i点有颜色数量为1的一个颜色
}
dfs(1, 0);
cout<<ans;
return 0;
}
大佬啊,我不会反正
6 买瓜
题目描述:
小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个瓜,每个瓜的重量为 Ai。小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈一刀。小蓝希望买到的瓜的重量的和恰好为 m。
请问小蓝至少要劈多少个瓜才能买到重量恰好为 m 的瓜。如果无论怎样小蓝都无法得到总重恰好为 m 的瓜,请输出 −1。
思路:dfs+剪枝(只能通过45%)
每个瓜只可能存在三种情况:
- 选择整一个瓜
- 被切后选择一半
- 不选择该瓜
dfs暴力求解之后剪枝优化:
- 当前方案切的刀数大于等于之前已知方案的最优解
- 如果该路径上包括未选择的瓜的重量总和不够m
- 当前已有的重量超过m,则当前方案非法
- 贪心trick:按瓜的重量从大到小排序
从上面的思路得出我们的数据结构:
- 后缀和数组
s[i]
- 传参:当前判断第u个瓜,目前已有的重量w,切的刀数cnt
代码:
cpp
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 33;
int a[N], s[N];
int ans=INF;
int m, n;
void dfs(int u, double w, int cnt) {
//当前方案有效
if(w == m) {
ans = min(ans, cnt);
return;
}
//已经遍历完成
if(u > n) return;
//当前方案不优
if(cnt > ans) return;
if(w + s[u] < m) return;
//选择列表
dfs(u + 1, w + a[u], cnt);//选整个瓜
dfs(u + 1, w + a[u] / 2.0, cnt + 1);//切且选半个瓜
dfs(u + 1, w, cnt);//不选该瓜
}
bool cmp(int x, int y) {
return x > y;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1, cmp);
//记录后缀和
for(int i = n; i >= 1; i--) s[i] = s[i + 1] + a[i];
dfs(1, 0.0, 0);
cout << (ans==INF? -1 : ans);
return 0;
}
标答给的动态规划。。。
7 异或和之和
题目描述:
给定一个数组 Ai ,分别求其每个子段的异或和,并求出它们的和。或者说,对于每组满足 1 ≤ L ≤ R ≤ n 的 L , R ,求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L, R 得到的结果加起来的值。
代码:
没有位运算优化,直接附上我的暴力代码,可以过90%
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 9;
using ll = long long;
ll a[N];
int main() {
int n;
cin >> n;
ll ans=0;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) {
ll sum=0;
for(int j = i; j <= n; j++) {
sum^=a[j];
ans+=sum;
}
}
cout<<ans;
return 0;
}
之后再更新完善吧,孩子没时间了。。。
8 网络稳定性
题目描述:
有一个局域网,由 n 个设备和 m 条物理连接组成,第 i 条连接的稳定性为w i 。对于从设备 A 到设备 B 的一条经过了若干个物理连接的路径,我们记这条路径的稳定性为其经过所有连接中稳定性最低的那个。
我们记设备 A 到设备 B 之间通信的稳定性为 A 至 B 的所有可行路径的稳定性中最高的那一条。
给定局域网中的设备的物理连接情况,求出若干组设备 x i 和 y i 之间的通信稳定性。如果两台设备之间不存在任何路径,请输出 −1 。
孩子先不想看了,这种图论的题太吃基础了。。。可以直接看题解
9 像素放置
小蓝最近迷上了一款名为《像素放置》的游戏,游戏在一个 n × m 的网格棋盘上进行,棋盘含有 n 行,每行包含 m 个方格。
玩家的任务就是需要对这n × m 个方格进行像素填充,填充颜色只有黑色或白色两种。有些方格中会出现一个整数数字 x(0 ≤ x ≤ 9),这表示当前方格加上周围八个方向上相邻的方格(分别是上方、下方、左方、右方、左上方、右上方、左下方、右下方)共九个方格内有且仅有 x 个方格需要用黑色填充 。
玩家需要在满足所有数字约束下对网格进行像素填充,请你帮助小蓝来完成。题目保证所有数据都有解并且解是唯一的。
思路:dfs+判断合法
代码:
cpp
#include <iostream>
using namespace std;
int n, m;
char d[12][12];//原始数组
int f[12][12];//填充后的数组
//检查是否合法
bool check(int x, int y) {
if(d[x][y] == '_') return true;
int cnt = 0;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) cnt += f[x + i][y + j];
}
// 如果周围1(黑棋)数量等于 d[x][y] 对应的数字,返回true,否则返回false
if(cnt == d[x][y] - '0') return true;
return false;
}
//深搜试探,从左往右,从上往下
void dfs(int x, int y) {
//检查是否符合最后一行
if(x == n + 1) {
for(int j = 1; j <= m; j++) {
if(!check(n, j)) return;
}
//找到答案,直接输出,结束
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cout << f[i][j];
}
cout << endl;
}
return;
}
//到该行的最后一列 准备换行
if(y == m) {
//尝试0
f[x][y] = 0;
if(x == 1 || (y == 1 && check(x - 1, y)) || (check(x - 1, y - 1) && check(x - 1, y))) {
dfs(x + 1, 1);
}
//尝试1
f[x][y] = 1;
if(x == 1 || (y == 1 && check(x - 1, y)) || (check(x - 1, y - 1) && check(x - 1, y))) {
dfs(x + 1, 1); //换行
}
}
//没到换行,遍历该行下一列
else {
f[x][y] = 0;
if(x == 1 || y == 1 || (check(x - 1, y - 1)))
dfs(x, y + 1);
f[x][y] = 1;
if(x == 1 || y == 1 || check(x - 1, y - 1))
dfs(x, y + 1);
}
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cin >> d[i][j];
}
}
dfs(1, 1);
return 0;
}
10 翻转硬币
这个的难度也是不想再吐槽了。。。直接借鉴的别人的50%的暴力:
思路:
转一个i位置不会影响到小于i的位置,所以暴力得从小到大,确保前面每个位置都已经被修改,那么久根据题意从2开始,遇到一个i位置是0,就开始把i的倍数的位置翻转即可。用一个tot记录需要翻转的位置数,根据翻转的情况来更改tot,如果某次执行后tot为0那么久代表已经全部为1,统计翻转次数即可。
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
bitset<200000001>t;
int main() {
int n;
cin >> n;
int ans = 1;
t[1] = 1;
int tot = n - 1;
for(int i = 2; i <= n; i++) {
if(t[i]) continue;
int j = i;
ans++;
while(j <= n) {
t[j] = !t[j];
if(t[j]) tot--;
else tot++;
j += i;
}
if(!tot) break;
}
cout << ans;
return 0;
}
自己模拟根本没时间看这道题。。。