ABC347 プログラミングコンテスト問題解説

A

link

很简单 配列を順にアクセスし、\(k\)で割った余りが\(0\)かどうか判定する。余りが\(0\)の場合、\(a_i/k\)を出力する。

クリックしてコードを表示``` #include<bits/stdc++.h>

using namespace std;

int n, k; int data[105];

int main() { cin >> n >> k;

for(int i = 1; i <= n; ++i) {
    cin >> data[i];
    if(data[i] % k == 0) {
        cout << data[i] / k << " ";
    }
}

return 0;

}


B
=

link

前置知識:\\(unordered\\_map\\)(または\\(map\\))
\\(unordered\\_map\\)は連想配列であり、キーに任意の型(文字列など)を使用できる。
、与えられた文字列的所有異なる部分文字列を数える問題。
部分文字列を列挙し、以前に出現したことがあるかどうかを確認する。
列挙方法:
外側の2重ループで部分文字列の開始位置と終了位置を指定し、内側のループで指定範囲内の文字を結合して部分文字列を作成する。
確認方法:
\\(unordered\\_map\\)を使用して、その文字列が既に存在するかを調べる。存在しない場合は答えをインクリメントし、マップに登録する。

クリックしてコードを表示```
#include<bits/stdc++.h>

using namespace std;

char text[105];
int length;
string substr;
unordered_map<string, int> seen;
int answer;

int main() {
    cin >> text + 1;
    length = strlen(text + 1);
    
    for(int i = 1; i <= length; ++i) {
        for(int j = i; j <= length; ++j) {
            substr.clear();
            for(int p = i; p <= j; ++p) {
                substr += text[p];
            }
            if(!seen[substr]) {
                seen[substr] = 1;
                answer++;
            }
        }
    }
    
    cout << answer;
    return 0;
}

C

link

まず、各要素を第1週の勤務日企业与第2週の休日にマッピングする。 その後、、第1週の勤務日から第2週の休日に移動できる要素を見つけ、移动过程中第2週の休日の範囲外に出てはいけない。 移动可能な要素の中で最大値と最小値を求める。移動後の最大値が休日の時間を超える場合、范围外に移動してしまうため不可。 別の方法として、从前面截取一段放到后面的方式来検討する。

クリックしてコードを表示``` #include<bits/stdc++.h>

#define int long long

using namespace std;

int n, work, rest; int timeData[200005]; int current, result = 1e18; int maximumVal, minimumVal = 1e18;

int main() { cin >> n >> work >> rest; for(int i = 1; i <= n; ++i) { cin >> current; current %= (work + rest); if(current == 0) current = work + rest; if(current <= work) { current += work + rest; } maximumVal = max(maximumVal, current); minimumVal = min(minimumVal, current); timeData[i] = current; }

sort(timeData + 1, timeData + 1 + n);

for(int i = 1; i < n; ++i) {
    result = min(result, work + rest - timeData[i+1] + timeData[i] + 1);
}

result = min(result, maximumVal - minimumVal + 1);
if(result <= work) cout << "Yes";
else cout << "No";

return 0;

}


D
=

link

まず、\\(c\\)のビット表現における1の个数を\\(cnt\\)とする。
場合分け:
- \\(cnt > a+b\\)の場合:不可
- \\(cnt = a+b\\)の場合:\\(a\\)個の1を最初の数に、\\(b\\)個の1を2番目の数に割り当てで対応するビット位置を决定する
- \\(cnt < a+b\\)の場合:残り(\\(a+b-cnt\\))が奇数なら不可、偶数なら可能
偶数の場合:首先、\\(a\\)と\\(b\\)から余分を平等のように去除し、その후残りの\\(a\\)個の1を最初の数に、\\(b\\)個の1を2番目の数に割り当てる。次に、\\(c\\)のビットが0の位置から足够的数を 찾아서両方の数を1にする。
注意:結果は\\(2^{60}\\)を超えない

クリックしてコードを表示```
#include<bits/stdc++.h>

#define int long long

using namespace std;

int A, B, C, bitCount;
int cbits[65];
int resultA[65], resultB[65];

int main() {
    cin >> A >> B >> C;
    
    int temp = C;
    for(int i = 0; i <= 59; ++i) {
        if(temp & 1) {
            cbits[i] = 1;
            bitCount++;
        }
        temp >>= 1;
    }
    
    if(bitCount > A + B || (A + B - bitCount) % 2 != 0) {
        cout << -1;
        return 0;
    }
    
    int extra = (A + B - bitCount) / 2;
    A -= extra;
    B -= extra;
    
    for(int i = 0; i <= 59; ++i) {
        if(cbits[i]) {
            if(A > 0) {
                resultA[i] = 1;
                A--;
            } else if(B > 0) {
                resultB[i] = 1;
                B--;
            }
        }
    }
    
    if(A < 0 || B < 0) {
        cout << -1;
        return 0;
    }
    
    for(int i = 0; i <= 59; ++i) {
        if(!cbits[i]) {
            if(extra > 0) {
                resultA[i] = 1;
                resultB[i] = 1;
                extra--;
            }
        }
    }
    
    if(extra > 0) {
        cout << -1;
        return 0;
    }
    
    int num1 = 0, num2 = 0;
    int weight = 1;
    
    for(int i = 0; i <= 59; ++i) {
        if(resultA[i]) num1 += weight;
        if(resultB[i]) num2 += weight;
        weight *= 2;
    }
    
    cout << num1 << " " << num2 << endl;
    
    return 0;
}

タグ: AtCoder abc347 C++ アルゴリズム 競技プログラミング

5月20日 03:09 投稿