AtCoder Beginner Contest 190解题报告

题目链接:abc190

A - Very Very Primitive Game

题目大意

  • Takahashi 和 Aoki吃糖果,轮流吃糖果,如果轮到的人没糖果了那么就输。
  • a是T拥有的糖果数,b是A拥有的糖果数,c=0说明T先吃,c=1说明A先吃。
  • 输出赢家 
  • 0≤A,B≤100

思路

  • A先吃说明T已经吃完一颗了,所以可以让a+c,那么就统一T先吃糖果了
  • 如果a>b则T赢,否则A赢

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
    int a, b, c;
    cin >> a >> b >> c;
    a += c;
    if(a > b) puts("Takahashi");
    else puts("Aoki");
    return 0;
}

B - Magic 3

题目大意

  • 魔术师打怪,n种咒语,每种咒语持续时间是ai,伤害是bi
  • 怪物能够承受最短时间是s,最大伤害是d
  • 问魔术师能够成功击杀怪物
  • 范围1≤N≤100, 1≤ai≤1e9, 1≤bi≤1e9, 1≤s≤1e9, 1≤d≤1e9

思路

  • 找所有咒语中是否有ai<s并且bi>d即可
  • 这里用了与运算

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
    int n, s, d, flag = 0;
    scanf("%d%d%d", &n, &s, &d);
    while(n --){
        int x, y;
        scanf("%d%d", &x, &y);
        flag |= (x < s && y > d);
    }
    if(flag) puts("Yes");
    else puts("No");
    return 0;
}

C - Bowls and Dishes

题目大意

  • 有n种菜,m种搭配a1, bi,k个人选菜,
  • 每个人都有两种选择ci ,di,选完之后看满足多少种搭配
  • 问最多满足多少搭配
  • 范围:2≤N≤100,1≤M≤100,1≤Ai<Bi≤N,1≤K≤16, 1≤Ci<Di≤N

思路

  • 状态压缩
  • 因为最多只有16个人,那么可以二进制枚举所有情况,0表示选第一个菜,1表示选择第二个菜,并标记vis数组
  • 然后遍历搭配,如果两者都存在,则cnt++,最后更新这个cnt最大值即可

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int a[105], b[105], c[105], d[105];
int vis[105];
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++){
        scanf("%d%d", &a[i], &b[i]);
    }
    int k; scanf("%d", &k);
    for(int i = 0; i < k; i ++){
        scanf("%d%d", &c[i], &d[i]);
    }
    int ans = 0;
    for(int t = 0; t < (1 << k); t ++){
        for(int i = 1; i <= n; i ++) vis[i] = 0;
        for(int i = 0; i < k; i ++){
            if((t >> i) & 1)  vis[d[i]] = 1;
            else vis[c[i]] = 1;
        }
        int cnt = 0;
        for(int i = 1; i <= m; i ++){
            if(vis[a[i]] + vis[b[i]] == 2) cnt ++;
        }
        ans = max(ans, cnt);
    }
    printf("%d\n", ans);
    return 0;
}

D - Staircase Sequences

题目大意

  • 给你一个n,问你能构成几个等差数列,公差d是1,数列的和是n?
  • 1≤N≤1e12

思路

  • 等差数列的求和公式是S=n*a0+n*(n-1)*d/2
  • d=1,那么S就与项数n和首项a0有关了,S已知,那么就用n表示a0: a0=S/n-(n-1)/2 -> 2a0=2S/n+1-n
  • a0是整数,所以需要满足2S/n+1-n是偶数,并且n是2S的因子。
  • 跑O(\sqrt{n})时间求出满足条件的n的个数即可。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
    ll n; cin >> n;
    int cnt = 0;
    n <<= 1;
    for(int i = 1; i <= sqrt(n); i ++){
        if(n % i == 0){
            if((n / i + 1 - i) % 2 == 0) cnt ++;
            ll d = n / i;
            if(i == d) continue;
            if((n / d + 1 - d) % 2 == 0) cnt ++;
        }
    }
    cout << cnt << endl;
    return 0;
}

F - Shift and Inversions

题目大意

  • 给你n个0到n-1全排列的数组,然后这个数组会循环左移n-1
  • 问你这个过程中数组的逆序数对是多少
  • 逆序数对,满足i<j, ai>aj 的对<i,j>的个数
  • 2≤N≤3×1e5

思路

  • 初始的逆序对ans用树状数组或者归并排序做,这里就用树状数组的了,
  • 然后比如{2, 0, 1, 3}这个对循环左移变成了{0, 1, 3, 2},就是2往后移了,那么现在,比2小的数移到了左边,逆序对就少了a1对,比2大的数也移到了左边,逆序对就多了a2对
  • 由于他是全排列,那么比2小的数a1就有2对,比2大的数a2就有4 - 1 - 2对,也就是说只需要ans - a1 + a2就行了。
  • 逆序对最大值是n*(n - 1) / 2所以会爆int,需要开long long

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & -x
const int maxn = 3e5 + 5;
int c[maxn], n;
void add(int x){
    for(int i = x; i <= n; i += lowbit(i))
        c[i] ++;
}
int query(int x){
    int ans = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        ans += c[i];
    return ans;
}
int a[maxn];
int main(){
    ll ans = 0; cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> a[i]; a[i] ++;
        //由于树状数组不能加0,所以a[i]需要加1,那么下面的d1就要对应的+1, d2要对应的-1
        add(a[i]);
        //query求的是小于等于a[i]的数的个数,i是现在有的个数
        //那么现在要求的是逆序对,也就是要求前面比他大的数的个数,那么就是i-query
        ans += i - query(a[i]); 
    }
    int d1 = 0, d2 = 0;
    for(int i = 1; i <= n; i ++){
        cout << ans << endl;
        d1 = n - a[i], d2 = a[i] - 1;
        ans += d1 - d2;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/113448497
今日推荐