X游戏
题目
我们称一个数X
为好数, 如果它的每位数字逐个地被旋转 180 度后,我们仍可以得到一个有效的,且和 X
不同的数。要求每位数字都要被旋转。
如果一个数的每位数字被旋转以后仍然还是一个数字, 则这个数是有效的。0
, 1
, 和 8
被旋转后仍然是它们自己;2
和 5
可以互相旋转成对方;6
和 9
同理,除了这些以外其他的数字旋转以后都不再是有效的数字。
现在我们有一个正整数 N
, 计算从 1 到 N
中有多少个数 X
是好数?
输入描述:
输入正整数N
输出描述:
输出1到N
中好数个数
样例:
10 >--------------------------------------------------< 4
解析
数据不大的时候模拟就行了;
数据很大的时候就要数位DP了,这里就不细说了。
#include <bits/stdc++.h>
int main()
{
for (int n; std::cin >> n;) {
int ans = 0;
for (int i = 1; i < n + 1; ++i) {
std::string str = [] (int n) -> std::string{
std::string ret;
for (; n; ret.push_back(n % 10 + '0'), n /= 10) {}
return ret;
}(i);
std::all_of(std::begin(str), std::end(str), [] (const char c) {
return c != '3' && c != '4' && c != '7';
}) &&
std::any_of(std::begin(str), std::end(str), [] (const char c) {
return c == '2' || c == '5' || c == '6' || c == '9';
}) ?
++ans : 0;
}
std::cout << ans << std::endl;
}
return 0;
}
跳格子游戏
题目
假设你正在玩跳格子(所有格子排成一个纵列)游戏。需要 跳完n
个格子你才能抵达终点。
每次你可以跳 1
或 2
个格子。你有多少种不同的方法可以到达终点呢?
注意:给定n
是一个正整数。
输入描述:
格子数n
输出描述:
跳完n
个格子到达终点的方法
样例:
2 >--------------------------------------------------< 2
解析
斐波拉契数列;
数据很大的时候要用矩阵快速幂加速,详情见深入浅出矩阵快速幂及其简单应用。
#include <bits/stdc++.h>
int main()
{
for (int n; std::cin >> n; ) {
long long f0 = 1, f1 = 1, t;
for (int i = 2; i <= n; t = f1, f1 += f0, f0 = t, ++i) {}
std::cout << f1 << std::endl;
}
return 0;
}
糖果分配
题目
假设你是一位很有爱的幼儿园老师,想要给幼儿园的小朋友们一些小糖果。但是,每个孩子最多只能给一块糖果。对每个孩子i
,都有一个胃口值 gi
,这是能让孩子们满足胃口的糖果的最小尺寸;并且每块糖果j
,都有一个尺寸sj
。如果 sj >= gi
,我们可以将这个糖果j
分配给孩子i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块糖果。
输入描述:
第一行输入每个孩子的胃口值
第二行输入每个糖果的尺寸
孩子数和糖果数不超过1000
输出描述:
能满足孩子数量的最大值
样例:
1 2 3 1 1 >--------------------------------------------------< 1
解析
贪心,尽量让每个孩子得到刚好合适的糖果。
#include <bits/stdc++.h>
int main()
{
std::string cindyString, childString;
std::getline(std::cin, childString);
std::getline(std::cin, cindyString);
std::vector<int> cindys, childs;
auto stringInput = [] (const std::string & str, std::vector<int> & vec) {
std::stringstream sin(str);
for (int x; sin >> x; vec.emplace_back(x)) {}
};
stringInput(childString, childs);
stringInput(cindyString, cindys);
std::sort(std::begin(cindys), std::end(cindys));
std::sort(std::begin(childs), std::end(childs));
int ans = 0;
for (auto it = std::begin(childs), start = std::begin(cindys);
it != std::end(childs) && start != std::end(cindys); ++it) {
auto pos = std::lower_bound(start, std::end(cindys), *it);
if (pos != std::end(cindys)) {
++ans;
start = pos + 1;
} else
start = pos;
}
std::cout << ans << std::endl;
return 0;
}
K点游戏
题目
小招喵某日闲来无事,想验一下自己的人品,于是给自己定了一个游戏规则:
这个游戏有三个因素:N,K,W
游戏开始的时候小招喵有0
点,之后如果发现自己手上的点不足K
点,就随机从1
到W
的整数中抽取一个(包含1
和W
),抽到哪个数字的概率都是相同的。
重复上述过程,直到小招喵获得了K
或者大于K
点,就停止获取新的点,这时候小招喵手上的点小于等于N
的概率是多少?
输入描述:
输入为3个整数,分别对应N,K,W
,中间用空格隔开
其中0 <= K <= N <= 10000
,1 <= W <= 10000
输出描述:
输出为概率值,保留5位小数
样例:
21 17 10 >--------------------------------------------------< 0.73278
解析
枚举最后一次取之前已经取了多少点,然后看看还要取多少点能满足>= K
并且<= N
就行了。
最后一次取了x
点的概率可以用记忆化搜索弄出来。
这题比较坑的地方在于保留5位小数,像代码中特殊处理一下才能过这个题。
#include <bits/stdc++.h>
double dfs(int sum, int w, std::vector<double> & dp)
{
if ((int)dp[sum] + 1)
return dp[sum];
double ret = 0;
for (int i = 1; i <= w && i <= sum; ++i) {
double s = dfs(sum - i, w, dp) / w;
ret += s;
}
return dp[sum] = ret;
}
int main()
{
for (int n, k, w; std::cin >> n >> k >> w; ) {
double ans = 0;
std::vector<double> dp(k + 1, -1);
dp[0] = 1;
for (int pre = 0; pre < k; ++pre) {
if (k - pre > w) continue;
ans += dfs(pre, w, dp) * ((std::min(n - pre, w) - (k - pre) + 1.0) / w);
}
std::stringstream sout;
sout << std::setprecision(5) << ans;
std::cout << sout.str().substr(0, 7) << std::endl;
}
return 0;
}
排队唱歌
题目
我们部门要排队唱歌,大家乱哄哄的挤在一起,现在需要按从低到高的顺序拍成一列,但每次只能交换相邻的两位,请问最少要交换多少次
输入描述:
第一行是N
(N<50000
),表示有N
个人
然后每一行是人的身高Hi
(Hi<2000000
,不要怀疑,我们以微米计数),持续N
行,表示现在排列的队伍
输出描述:
输出一个数,代表交换次数。
样例:
6 3 1 2 5 6 4 >--------------------------------------------------< 4
解析
这题翻译过来就是,冒泡排序交换的次数,答案是序列的逆序对数。如何求逆序对呢?请参考序列逆序对问题详解。
这题的代码就是上面博客的代码。
#include <bits/stdc++.h>
class Solution {
public:
int InversePairs(std::vector<int> data) {
std::vector<int> pos(data.size()), arr(data);
sort(data.begin(), data.end());
for (int i = 0; i < (int)pos.size(); i++)
pos[i] = lower_bound(data.begin(), data.end(), arr[i]) - data.begin();
int c[(const int)data.size() + 1];
memset(c, 0, sizeof(c));
long long ret = 0;
for (int i = 0; i < (int)data.size(); i++)
add(c, pos[i] + 1, data.size()),
ret = (ret + i + 1 - getsum(c, pos[i] + 1));
return (int)ret;
}
int lowbit(int x)
{
return x & -x;
}
long long getsum(int c[], int i)
{
long long ret = 0;
for (; i > 0; i -= lowbit(i))
ret = (ret + c[i]);
return ret;
}
void add(int c[], int i, int n)
{
for (; i <= n; i += lowbit(i))
++c[i];
}
};
int main()
{
for (int n; std::cin >> n;) {
std::vector<int> arr(n);
for (int i = 0; i < n; std::cin >> arr[i++]) {}
Solution sol;
std::cout << sol.InversePairs(arr) << std::endl;
}
return 0;
}