AtCoderビギナーコンテスト190問題解決レポート

トピックリンク:abc190

A-非常に原始的なゲーム

トピック

  • 高橋さんと青木さんはお菓子を食べ、交代でお菓子を食べ、順番にお菓子がないと負けます。
  • aはTが所有するキャンディーの数、bはAが所有するキャンディーの数、c = 0はTが最初に食べることを意味し、c = 1はAが最初に食べることを意味します。
  • 出力の勝者 
  • 0≤A、B≤100

アイデア

  • 最初に食べるAは、Tが1つ食べたことを意味するので、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-マジック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-ボウルと料理

トピック

  • n種類の料理、m種類のコロケーションa1、bi、kの個別選択料理があります。
  • 誰もがciとdiの2つの選択肢を持っています。選択した後、満足しているコロケーションの数を確認してください
  • 最大でいくつの試合が行われるかを尋ねる
  • 範囲:2≤N≤100、1≤M≤100、1≤Ai <Bi≤N、1≤K≤16、1≤Ci <Di≤N

アイデア

  • 状態圧縮
  • 最大で16人しかないため、すべての状況をバイナリで列挙できます。0は最初の料理を選択することを意味し、1は2番目の料理を選択することを意味し、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-階段シーケンス

トピック

  • 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-シフトと反転

トピック

  • 0からn-1までのn個の配列を指定すると、この配列は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が爆発し、longlongを開く必要があります。

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