今回、ある理由からC問題はKotlinを使ってみました。
A – 流行
文章の通りです。入力*2を出力すればOKです。
#include<bits/stdc++.h>
using namespace std;
int main(){
int N;
cin>>N;
cout<<2*N<<endl;
}
B – 回転
180度回転するということは、Y軸X軸ともに反転するということです。
なので、以下のように出力すればOKです。
c3,3 c3,2 c3,1 c3,0 c2,3 c2,2 c2,1 c2,0 c1,3 c1,2 c1,1 c1,0 c0,3 c0,2 c0,1 c0,0
#include<bits/stdc++.h>
using namespace std;
int main(){
char c[4][4];
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cin>>c[i][j];
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cout<<c[3-i][3-j];
if(j==3) cout<<endl;
else cout<<" ";
}
}
}
C – 入れ替え
一番簡単な方法は愚直にシミュレーションする方法ですが、O(N)のためTLEしてしまいます。
部分点のN<=50ではTLEしないため、部分点は取得できます。
#include<bits/stdc++.h>
using namespace std;
int main(){
int N;
cin>>N;
int c[6]={1,2,3,4,5,6};
for(int i=0;i<N;i++){
swap(c[i%5],c[i%5+1]);
}
cout<<c[0]<<c[1]<<c[2]<<c[3]<<c[4]<<c[5]<<endl;
}
制限時間ギリギリでACしちゃいました\(^o^)/
さすがC++ですね。O(10^9)でも簡易な処理だと2s以内で終わっちゃうようです。
これだと消化不良感があるので、上記コードをKotlinで書きなおしました。
fun main(args: Array<String>) {
val n = readLine()!!.toInt()
val c = arrayOf(1,2,3,4,5,6)
for(i in 0 until n){
var tmp=c[i%5]
c[i%5]=c[i%5+1]
c[i%5+1]=tmp
}
for(i in 0 until 6){
print(c[i])
}
}
無事(?)TLEしました。
ここから速度改善をします。
Nを増やしたときの動きを観察します。
N=1 213456 N=2 231456 N=3 234156 ... N=29 123465 N=30 123456 N=31 213456
どうもN=30でループしているようです。
つまり、31回の操作後の配列=1回の操作後の配列となります。
30回操作することは無駄であるため、%30で剰余を取った数だけシミュレーションすればOKです。
fun main(args: Array<String>) {
val n = readLine()!!.toInt()%30
val c = arrayOf(1,2,3,4,5,6)
for(i in 0 until n){
var tmp=c[i%5]
c[i%5]=c[i%5+1]
c[i%5+1]=tmp
}
for(i in 0 until 6){
print(c[i])
}
}
D – マーブル
R,G,Bそれぞれのマーブルを一番近い場所に愚直に置いていくやり方が良さそうです。
(Rなら、-100,-99,-101,-98,-102…と順に近いほうに送っていく)
この解法で1<=RGB<=40の30点はOKです。
#include<bits/stdc++.h>
using namespace std;
int main(){
int R,G,B;
cin>>R>>G>>B;
int ans=0;
R--;
G--;
B--;
for(int i=1;R>0;i++){
ans+=i*min(2,R);
R-=2;
}
for(int i=1;G>0;i++){
ans+=i*min(2,G);
G-=2;
}
for(int i=1;B>0;i++){
ans+=i*min(2,B);
B-=2;
}
cout<<ans<<endl;
}
ただ、満点解法の場合NGです。というのもマーブルの数が多い場合、どこかでぶつかってしまうからです。
全探索を単純にするとTLEのため、一つ基準のマーブルを決め、それを全探索します。
真ん中のマーブルの位置が決まれば、左右のマーブルは簡単に決まりそうだったため、Gのマーブルをどこに置くかを全探索。それを元にR,Bのマーブルの位置を決めて最小を取る…
としたかったのですが、以下のACコードをご参照ください。
#include<bits/stdc++.h>
using namespace std;
int main(){
int R,G,B;
cin>>R>>G>>B;
int ans=INT_MAX;
//900,1000,1100で考える
for(int i=1000-G;i<=1000+1;i++){
int tR=R;
int tB=B;
int f[2000]={0};
int c=0;
for(int j=i;j<=i+G-1;j++){
f[j]=1;
c+=abs(1000-j);
}
if(f[900]==0) {
f[900]=1;
tR--;
}
bool tobi=true;
for(int j=1;tR>0;j++){
if(f[900+j]==0&&tobi){
f[900+j]=1;
tR--;
c+=j;
}
else tobi=false;
if(tR<=0) break;
if(f[900-j]==0){
f[900-j]=1;
tR--;
c+=j;
}
if(tR<=0) break;
}
if(f[1100]==0) {
f[1100]=1;
tB--;
}
tobi=true;
for(int j=1;tB>0;j++){
if(f[1100+j]==0){
f[1100+j]=1;
tB--;
c+=j;
}
if(tB<=0) break;
if(f[1100-j]==0&&tobi){
f[1100-j]=1;
tB--;
c+=j;
}
else tobi=false;
if(tB<=0) break;
}
ans=min(c,ans);
c=0;
for(int j=0;j<2000;j++) f[j]=0;
for(int j=i;j<=i+G-1;j++){
f[j]=1;
c+=abs(1000-j);
}
tR=R;
tB=B;
if(f[900]==0) {
f[900]=1;
tR--;
}
for(int j=1;tR>0;j++){
if(f[900+j]==0){
f[900+j]=1;
tR--;
c+=j;
}
if(tR<=0) break;
if(f[900-j]==0){
f[900-j]=1;
tR--;
c+=j;
}
if(tR<=0) break;
}
if(f[1100]==0) {
f[1100]=1;
tB--;
}
for(int j=1;tB>0;j++){
if(f[1100+j]==0){
f[1100+j]=1;
tB--;
c+=j;
}
if(tB<=0) break;
if(f[1100-j]==0){
f[1100-j]=1;
tB--;
c+=j;
}
if(tB<=0) break;
}
ans=min(c,ans);
}
cout<<ans<<endl;
}
ヤバそうでしょ?実際ヤバいです。
Gは連続している(GGGRGGGみたいに割り込む配置や、GGG空GGGみたいに間に何も入っていない箱がない)のが最適と考え、連続区間を-G~Gの範囲内で動かしました。
残りのRとBは近いところにマーブルを置いていくのですが、この際、飛越を許容するかしないかの2パターン求めました。(RRRGGGRRBBBみたいなパターン)
全探索の場合、思いのほか考えるケースが多かったです。
Atcoderの公式解説を見たのですが、DPで求めるのが一番素直かな?と思いました。
(後で解いておきます> <)
コメント
[…] […]