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
对于组合问题最好放到坐标轴上;
官方题解:
image
对于所有的摆放方式,就是从(0, 0)走到(m, n)的方案数,如果超过了y = x + k这条直线,那么这个方案就不可用。
可以从图中看出,一旦终点的n > m + k,那么无论如何都不可能有解,所以当n > m + k时,无解

image
当不考虑条件时,所有的排列方式是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;
}
posted on 2021-06-14 17:04  Laurance  阅读(147)  评论(0编辑  收藏  举报