AtCoder Beginner Contest 205
链接:https://atcoder.jp/contests/abc205/tasks
rank:3083
AC:ABCD
A - kcal
意思是给定两个数A, B, A指的是这种饮料100毫升含有的能量,现在要求计算出B毫升这种饮料所含有的能量,要求误差要在10^-6以内
直接计算即可
代码
#include <iostream>
using namespace std;
int main()
{
double a, b;
cin >> a >> b;
double res = a / 100 * b;
printf("%lf\n", res);
return 0;
}
B - Permutation Check
意思是给定一个n和n个数,要求确定这些数是不是1到n的一个排列
O(n)扫描一遍记录每个数字是不是出现过,然后从1到n扫描一遍是不是有没有出现过的数
代码
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];
int n;
bool st[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> a[i];
for (int i = 0; i < n; i ++ ) st[a[i]] = true;
bool flag = true;
for (int i = 1; i <= n; i ++ )
if (!st[i]) flag = false;
if (flag) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
C - POW
给定两个数A,B和一个次幂C,要求判断A和B的C次幂哪个大
先确定C是奇数还是偶数,如果是奇数那么A和B谁比较大那答案就是谁,若C是偶数,那么先求出绝对值,绝对值较大的就是答案
代码
#include <iostream>
using namespace std;
int main()
{
int a, b, c;
cin >> a >> b >> c;
if (c % 2)
{
if (a > b) cout << ">" << endl;
else if (a < b) cout << "<" << endl;
else cout << '=' << endl;
}
else
{
a = abs(a);
b = abs(b);
if (a > b) cout << ">" << endl;
else if (a < b) cout << "<" << endl;
else cout << '=' << endl;
}
return 0;
}
D - Kth Excluded
题目给出n个数和q组询问,每一次给出一个数k,要求找出不在这n个数中的第k大的数
先处理出来给定的数里面每个数之前有多少个没有被标记过的数,然后二分即可,如果二分出来发现结果在n个数之内,那么找到第一个满足条件的数,从这里开始倒着数回去。若二分之后发现答案不在这n个数中,那么就从最大的那个数开始往后数k - cnt个数即可,其中cnt代表a[n]前面没有被标记过的数有多少个
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, q;
long long a[N];
long long b[N];
long long max_;
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i ++ )
{
scanf("%lld", &a[i]);
b[i] = a[i] - i;
max_ = max(max_, a[i]);
}
while (q -- )
{
long long k;
scanf("%lld", &k);
long long l = 1, r = n + 1; // 有边界设置成n + 1, 答案不在n以内便于判断
while (l < r)
{
long long mid = l + r >> 1;
if (k <= b[mid]) r = mid;
else l = mid + 1;
}
if (l == n + 1) cout << k - b[n] + max_ << endl;
else cout << a[l] - (b[l] - k) - 1 << endl; // 倒着往前数
}
return 0;
}
E - White and Black Balls
给定n个白球和m个黑球还有一个数字k,问有多少种排列方式满足条件,条件是对于每一个位置上的i,令w[i]是这个球左边的白球数,b[i]是这个球左边的黑球数,需要使得w[i] <= b[i] + k
对于组合问题最好放到坐标轴上;
官方题解:
对于所有的摆放方式,就是从(0, 0)走到(m, n)的方案数,如果超过了y = x + k这条直线,那么这个方案就不可用。
可以从图中看出,一旦终点的n > m + k,那么无论如何都不可能有解,所以当n > m + k时,无解
当不考虑条件时,所有的排列方式是c(n + m, n),那么考虑不满足条件的方案数,可以发现,不满足条件的方案都会碰到y = x + k + 1这条线,也就是说,不满足条件的方案数就是从(0, 0)走到(m, n),并且途中碰到过直线的方案数,这里就可以利用对称性,需要求的方案数就是原点关于直线的对称点(-k - 1, k + 1)走到(m, n)的方案数,即c(n + m, m + k + 1)
综上:当n <= m + k时,方案数为:c(m + n, n) - c(m + n, m + k + 1)
注意,这里的数据范围是2000000,所以求组合数要用O(n)的方式,并且预处理的时候不能处理到2000010,否则会超时
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 2000010, mod = 1e9 + 7;
LL fact[N];
LL infact[N];
int n, m, k;
LL qmi(LL a, LL k)
{
LL res = 1;
while (k)
{
if (k & 1) res = res * a % mod;
a = a * a % mod;
k >>= 1;
}
return res;
}
void init()
{
fact[0] = infact[0] = 1;
for (int i = 1; i <= 2000000; i ++ )
{
fact[i] = fact[i - 1] * i % mod;
infact[i] = infact[i - 1] * qmi(i, mod - 2) % mod;
}
}
LL c(int a, int b)
{
return fact[a] * infact[a - b] % mod * infact[b] % mod;
}
int main()
{
init();
scanf("%d%d%d", &n, &m, &k);
if (n > m + k) puts("0");
else
{
LL ans = (c(n + m, m) - c(m + n, m + k + 1) + mod) % mod;
printf("%lld\n", ans);
}
return 0;
}