🔵
【ABC365】AtCoder Beginner Contest 365【C++】
コンテスト名
トヨタ自動車プログラミングコンテスト2024#8(AtCoder Beginner Contest 365)
コンテストURL
開催日
2024/08/03 21:00-22:40
A: Leap Year
解法
- 問題文通りに判定する
ABC365A.cpp
#include <iostream>
using namespace std;
int main(){
int y;
cin >> y;
if(y%4!=0){
cout << 365 << endl;
}else if(y%100!=0){
cout << 366 << endl;
}else if(y%400!=0){
cout << 365 << endl;
}else{
cout << 366 << endl;
}
return 0;
}
B: Second Best
解法
-
vector<pair<int, int>>
で要素の値と位置を記録する - 降順にソートして 2 番目に大きい要素を取得する
ABC365B.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
vector<pair<int, int>> A;
int a;
for(int i=0; i<n; i++){
cin >> a;
A.emplace_back(a, i+1);
}
sort(A.rbegin(), A.rend());
auto [value, num] = A[1];
cout << num << endl;
return 0;
}
C: Transportation Expenses
解法
- 累積和を利用して仮の上限額を求める
- 交通費の配列
を昇順にソートして累積和を求めるA - 仮の上限額
をx' のなかから選ぶA_i - 交通費が仮の上限額
以下の人x' にはi 円が支給されるため、累積和を利用して合計を求めるA_i - 交通費が仮の上限額
より大きい人にはx' 円が支給されるため、(交通費が仮の上限額x' より大きい人の人数x' )を求める\times \ x' -
円からこれらの総和を引いた残りの分を交通費が仮の上限額M より大きい人に分配するx' -
の最大値をA にしたときでも交通費補助額の総和がx 円以下になるならば、答えは無限になるM -
の最小値を仮の上限額A にしたときでも条件を満たせない場合は、x' が答えである\lfloor \frac{M}{N} \rfloor - 計算量は
O(N \log N)
- 交通費の配列
- 答えを二分探索で求める
- 交通費の配列
を昇順にソートして答えを二分探索で求めるA - 計算量は
O(N \log (\text{max}A))
- 交通費の配列
ABC365C_1.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
long long int m;
cin >> n >> m;
vector<long long int> A(n), S(n);
for(int i=0; i<n; i++){
cin >> A[i];
S[i] = A[i];
}
sort(A.begin(), A.end());
sort(S.begin(), S.end());
for(int i=1; i<n; i++){
S[i] += S[i-1];
}
for(int i=n-1; i>=0; i--){
long long int sum = S[i];
sum += A[i] * (n - 1 - i);
if(sum<=m){
if(A[i]==A[n-1]){
cout << "infinite" << endl;
}else{
cout << A[i] + (m - sum)/(n - 1 - i) << endl;
}
return 0;
}
}
cout << m / n << endl;
return 0;
}
ABC365C_2.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
long long int m;
cin >> n >> m;
vector<int> A(n);
for(int i=0; i<n; i++){
cin >> A[i];
}
sort(A.begin(), A.end());
int low = 0, high = A.back() + 1;
while(high-low>1){
int mid = low + (high - low)/2;
long long int sum = 0;
for(int i=0; i<n; i++){
sum += min(mid, A[i]);
}
if(sum<=m){
low = mid;
}else{
high = mid;
}
}
if(low>=A.back()){
cout << "infinite" << endl;
}else{
cout << low << endl;
}
return 0;
}
D: AtCoder Janken 3
解法
- 動的計画法 (DP)
-
:=\text{dp}[i][j] 回目に手i を出すときの勝った回数の最大値j -
とすると、\text{R} = 0, \text{P} = 1, \text{S} = 2 回目の結果から求められるi - 1 - 相手が
回目にi を出したとき\text{R} = 0 - あいこ:
\text{dp}[i][0] = \text{max}(\text{dp}[i-1][1], \text{dp}[i-1][2]) - 勝ち:
\text{dp}[i][1] = \text{max}(\text{dp}[i-1][0], \text{dp}[i-1][2]) + 1
- あいこ:
- 相手が
ABC365D.cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
string s;
cin >> s;
vector<vector<int>> dp(n+1, vector<int>(3));
for(int i=0; i<n; i++){
if(s[i]=='R'){
dp[i+1][0] = max(dp[i][1], dp[i][2]);
dp[i+1][1] = max(dp[i][0], dp[i][2]) + 1;
}else if(s[i]=='P'){
dp[i+1][1] = max(dp[i][0], dp[i][2]);
dp[i+1][2] = max(dp[i][0], dp[i][1]) + 1;
}else if(s[i]=='S'){
dp[i+1][2] = max(dp[i][0], dp[i][1]);
dp[i+1][0] = max(dp[i][1], dp[i][2]) + 1;
}
}
int ans = 0;
for(int i=0; i<3; i++){
ans = max(ans, dp[n][i]);
}
cout << ans << endl;
return 0;
}
Discussion