ABC #019参加しました。
ABCもARCと同じく、公式解説があるので説明は最小限です。
A – 高橋くんと年齢
問題概要
3つの数字が与えられるので中央値を答える。
解法
与えられる数値が3つなので、条件分岐で他の値以上、他の値以下の数値を判定しても問題無いです。また、単純にソートして2つ目の値を出力しても解けます。
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
int main(int argc, char *argv[]) | |
{ | |
int a[3]; | |
cin>>a[0]>>a[1]>>a[2]; | |
sort(a,a+3); | |
cout<<a[1]<<endl; | |
return 0; | |
} |
B – 高橋くんと文字列圧縮
問題概要
文字列が与えられるので、その文字列で同じ文字が連続する箇所を[文字][繰り返し回数](ex. aaa -> a3)のような形式に変換して出力する。
解法
文字列の先頭から文字が連続している回数をカウントして、違う文字の箇所、または文字列の終端まできたら手前の文字と回数を出力すればOKです。
今回、答えを一回別のString変数に保存していますが、普通にC++ でやろうとするとint->stringの変換でsstreamやsprintfを使う等、ちょっと一手間かかります。ただ、C++11から変換関数が追加されているので、今回はそれを使用しています。ただ今回の問題であれば、別に変換しなくてもintのまま標準出力に出力してもOKです。
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
int main(int argc, char *argv[]) | |
{ | |
string s; | |
cin>>s; | |
string ans; | |
char tmp=s[0]; | |
int cnt=1; | |
for(int i=1;i<=s.size();i++) | |
{ | |
if(i==s.size() || tmp!=s[i]) | |
{ | |
ans+=tmp; | |
ans+=to_string(cnt); | |
if(i<s.size()) | |
{ | |
tmp=s[i]; | |
cnt=1; | |
} | |
} | |
else | |
cnt++; | |
} | |
cout<<ans<<endl; | |
return 0; | |
} |
C – 高橋くんと魔法の箱
問題概要
ある整数を入れると、その整数に対応する違う整数を返す箱がある。箱にxを入れた場合と2xを入れた場合、同じ数値が返ってくる。
N個の整数を箱に入れた時に、何種類の整数が返ってくるか答える。
解法
2xを入れた時とxを入れた時の値が同じなので、1度値を入れた際にその値を2で割り切れる間の数値でできる値は全て同じになります。
その元になるxの値を全てhashに保存しながら、すでにその値をチェックしていないかを確認して、はいっていなければその種類の数値は今まで発生していないため、種類のカウントを1増やし、全ての数値をチェックした後のカウントの値を返せばOKです。
(ただ、後で公式解説聞いてよく考えたら、値を割り終わるまで高々30回程度なので、途中結果をhashに入れなくても問題ありませんでした。)
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
int main(int argc, char *argv[]) | |
{ | |
int n; | |
set<int> hash; | |
int ans=0; | |
cin>>n; | |
for(int i=0;i<n;i++) | |
{ | |
int tmp; | |
cin>>tmp; | |
bool flag=true; | |
if(hash.count(tmp)!=0) | |
flag=false; | |
hash.insert(tmp); | |
while(tmp%2==0 && flag) | |
{ | |
tmp/=2; | |
if(hash.count(tmp)!=0) | |
{ | |
flag=false; | |
break; | |
} | |
hash.insert(tmp); | |
} | |
if(flag) | |
ans++; | |
} | |
cout<<ans<<endl; | |
return 0; | |
} |
D – 高橋くんと木の直径
問題概要
ある重み付き根なし無向木がある。この木に対して2点間の距離を質問することができる。
木の任意の2点間の距離の最大値(木の直径)を求める。
ただし、質問の回数は100回以下とする。(部分点:質問回数:1300回)
解法
部分点解法の場合は、全ての2点間を質問しても質問回数は1300回を超えない(i=jやi,j とj,iを別個で聞かない場合)ので、全ての2点間についての距離を質問して、その最大値が答えです。
満点解法の場合、木の直径を求める方法としてdouble-sweep法という方法があります。ある1点と他の点の距離を調べ、最も遠い点を探します。そしてその点から最も遠い2点の距離が木の直径となります。(今回の問題であればN<=50なので、最大でも49+48=97回で解くことができます。)
私はこのやり方を知らなかった(あるいはどこかでやっても忘れてる)ため、本番後に公式解説を聞いてやっと解けました。なので、この方法の証明などは公式解説スライド等を参考にしてください。
(制約から2点*他の点の処理をしそうということまでは行けたのですが…)
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
int main(int argc, char *argv[]) | |
{ | |
int n; | |
cin>>n; | |
long long int ans=0; | |
for(int i=1;i<n;i++) | |
for(int j=i+1;j<=n;j++) | |
{ | |
cout<<"? "<<i<<" "<<j<<endl; | |
long long int tmp; | |
cin>>tmp; | |
ans=max(ans,tmp); | |
} | |
cout<<"! "<<ans<<endl; | |
return 0; | |
} |
- 20点解法(本番中の回答)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
int main(int argc, char *argv[]) | |
{ | |
int n; | |
cin>>n; | |
long long int ans=0; | |
int num; | |
for(int i=2;i<=n;i++) | |
{ | |
cout<<"? "<<1<<" "<<i<<endl; | |
long long int tmp; | |
cin>>tmp; | |
if(tmp>ans) | |
{ | |
ans=tmp; | |
num=i; | |
} | |
} | |
for(int i=1;i<=n;i++) | |
{ | |
if(i==num) | |
continue; | |
cout<<"? "<<num<<" "<<i<<endl; | |
long long int tmp; | |
cin>>tmp; | |
ans=max(ans,tmp); | |
} | |
cout<<"! "<<ans<<endl; | |
return 0; | |
} |
- 満点解法(本番後の解き直し)