質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

661閲覧

AtCoder ABC162 D問題 RGB Triplets

shibahama

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/05/27 10:04

編集2020/05/27 13:08

#はじめに
閲覧ありがとうございます。前回同様、AtCoderさんの過去問から質問です。

#問題文
ABC162-D問題です。

#自分が立てた方針
①文字列のn文字目がR、G、Bのいずれかを判定し、Rの配列、Gの配列、Bの配列にnをpush_back
②Rの配列、Gの配列、Bの配列から1つずつ選ぶ全探索により条件に合致する組み合わせの個数を数える

#コード

C++

1#include <bits/stdc++.h> 2#include <vector> 3using namespace std; 4#define rep(i, n) for(int i = 0; i < n; ++i) 5#define ll long long 6 7int main() { 8 int n; 9 string s; 10 cin >> n >> s; 11 12 //配列の宣言 13 vector<int> r, g, b; 14 r.reserve(4000); g.reserve(4000); b.reserve(4000); 15 16 //方針①の操作 17 rep(i, n) { 18 char c = s[i]; 19 if(c == 'R') r.push_back(i); 20 else if(c == 'G') g.push_back(i); 21 else if(c == 'B') b.push_back(i); 22 } 23 24 25 int result = 0; 26 int rsize = r.size(); 27 int gsize = g.size(); 28 int bsize = b.size(); 29 30 //方針②の操作 31rep(i, rsize) { 32 rep(j, gsize) { 33 rep(k, bsize) { 34 int R = r[i]; 35 int G = g[j]; 36 int B = b[k]; 37 38 int large = max(R, max(G, B)); 39 int small = min(R, min(G, B)); 40 int medium = R + G + B - large - small; 41 42 if(large - medium != medium - small) ++result; 43 } 44 } 45 } 46 47 48 cout << result << endl; 49 return 0; 50}

#その他
テストケース1は通りましたが、2は通りませんでした。
解説生放送とは方針がちょっと違ったので、このコードの間違えを探す術がないのです(泣)

#追記・編集
5/27 19:40 !=の件を編集しました
5/27 21:11 方針②において、ijkの大小関係について編集しました

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/05/27 10:29

> 解説生放送とは方針がちょっと違ったので、このコードの間違えを探す術がないのです(泣) 何を言っているのか,全く意味がわかりません.
shibahama

2020/05/27 10:39

プログラミング初心者には「模写」という最後の砦があるのですが、それが使えないという意味です() そんなに大した意味は込めてません、ごめんなさい????
fana

2020/05/27 11:17

> 模写 の是非等には触れませんが, せっかくご自身で方針を打ち立てたのですから, ・実装したコードがその方針通りの動作をしているか? という動作確認 ・その方針で問題を解けるのか? という話の内容自体の確認 をするところまで取り組まれると良いのではないかと考えます. せめて,上記の「どちら側に問題があるのか」という切り分けをすべきです.(他者にはその判断はつきませんし)
shibahama

2020/05/27 11:26

ありがとうございます。今回ですと下の「その方針で問題を解けるのか」に問題があったようです。
guest

回答4

0

ベストアンサー

//方針②の操作
rep(i, rsize) {
rep(j, gsize) {
rep(k, bsize) {
if(b[k] - g[j] == g[j] - r[i]) ++result;
}
}
}

ここが
題意に沿った判定を行っているように見えないのですが…?
どこが間違っているか? と問うには,
「何故この処理でやれる(と考える)のか?」という,あなたの考え(アルゴリズム)を説明する必要があるのではないでしょうか.
例えば,問題文に記載された条件全てを何の工夫もなく愚直に実装するとしたら,以下のようになると思いますが,このような愚直な状態と比較して「どのような工夫を行っているのか?」という話が.

C++

1//※入力がめんどくさいので代替 2const std::string S = "RBRBGRBGGBBRRGBBRRRBGGBRBGBRBGBRBBBGBBB"; 3const int N = (int)S.size(); 4 5//愚直なカウント 6unsigned int Ans = 0; 7for( int i=0; i<N-2; ++i ) 8{ 9 for( int j=i+1; j<N-1; ++j ) 10 { 11 if( S[i] == S[j] )continue; 12 int dij = j - i; 13 for( int k=j+1; k<N; ++k ) 14 { 15 if( k-j == dij )continue; 16 if( S[i]==S[k] || S[j]==S[k] )continue; 17 ++Ans; 18 } 19 } 20} 21std::cout << Ans << std::endl;

投稿2020/05/27 10:22

編集2020/05/27 10:28
fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shibahama

2020/05/27 11:24

愚直なカウントだと4000C3≒10^10通りの全探索が必要なので、制限時間に間に合わないと思いました。よって、これよりも少ない数の全探索で終わるように、方針②を考えたのですが。。。。 ①で作った配列からそれぞれ1つずつ選び、その数の組でi、j、kを作ればR、G、Bが1つずつの組になるので、愚直なカウントより計算量が少なくなると考えました。 このとき、 ーーーーーーーーーーーーーー iとjとkの大小関係を意識していないのが原因...!? ーーーーーーーーーーーーーー これが原因でした。 ```C++ //方針②の操作 rep(i, rsize) { rep(j, gsize) { rep(k, bsize) { int R = r[i]; int G = g[j]; int B = b[k]; int large = max(R, max(G, B)); int small = min(R, min(G, B)); int medium = R + G + B - large - small; if(large - medium != medium - small) ++result; } } } ```
shibahama

2020/05/27 11:41

失礼、これだとTLEが2件でてしまいました。方針を立て直してみます。
guest

0

問題点1
j-i != k-j な組の数を求めなければいけません。j-i == k-j ではありません


以下追記
問題点2
i, j, k は i < j < k という関係ですが、それぞれ R, G, B であるとは決まっていません。
なので、i = r[i] と置き換えるのは誤りです。
r[x], g[y], b[z] で3重ループにするのはいいですが、それぞれを i < j < k となるように並べ替える必要があります。


追記2
問題点3
n <= 4000 なので、char では入りません

vector<char> r, g, b;

投稿2020/05/27 10:20

編集2020/05/27 12:20
yuki23

総合スコア1448

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/05/27 10:31

質問コードの問題点は,そんな簡単な話ではないと思う.
shibahama

2020/05/27 10:38

ごめんなさい、(失敗した)改良コードの1部が残ってました…。 正しいコード(正しいけど上手くいかないコード)は仰る通り!=です。
shibahama

2020/05/27 12:08

毎度申し訳ない、後者の件もfanaさんとの返信欄で解決し、実装しましたが、1部のテストケースでWAが改善されませんでした…。 まだじっくり考える必要があるようです…????‍♂️
shibahama

2020/05/27 12:23

>>問題点3 なんでchar型にしていたのかも、なんでchar型で半分以上ACとってたのも謎なんですが、これでTLE以外はACになりました...!!
yuki23

2020/05/27 12:32

TLEまで解決するのは、そもそも3重ループで全探索するという方針に無理があるので、これ以上は難しいです。解説の方針に倣ってくださいとしか。
shibahama

2020/05/27 13:06

そうですよねぇ ...。計算量を再計算したら10^9超えてたんで、どうもがいてもこの方針だと最悪ケースでTLE以外は免れないようです...。お騒がせしました!ミスを見つけてくださってありがとうございます!
guest

0

AtCoderはテストケースを公開しているのでそこから確かめられるかなと思います。

https://atcoder.jp/posts/20

投稿2020/05/27 10:16

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

【質問者です】

最大4000文字の文字列から3つを選ぶ場合、4000C3=10^10通り以上のループを回さなければならないのでら今回のような方針を取って探索回数を削減しようと考えました。しかし、後からもう一度計算してみると、4000文字のうちRとGとBがそれぞれ同じ数出現するとした場合、この方針でも(4000/3)^3=2×10^9以上のループが必要で、制限時間に間に合わないことが分かりました。(多少は改善されてるのですが…。)

今回は質問時点で私の考えた方針を実装する上でのコードバグが何ヶ所かあったのですが、それをご指摘頂き改善したところで、この質問の解決とさせて頂きます。

・立てた方針に沿うコードが実装できていなかった→ご指摘頂き改善された。
・方針について見直したところ、この方針では制限時間に間に合わないことが分かった。

yuki23さんに数か所バグをご指摘いただきましたので、質問本文にはそれを反映させてあります。

投稿2020/05/27 13:12

編集2020/05/28 12:06
shibahama

総合スコア7

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/05/28 01:40

本件の「解決」とは何なのか? という点に関しては色々な考え方があるとは思いますが… 「考えていた方針ではダメだった」というのを「解」として締めるのであれば, 各コメント欄に書かれた「どうダメなのか?」「なぜダメなのか?」ということを纏めるような方向だと良いのかもしれません. 質問時点では「自身の方針」の実装としてもバグっていた →最終的に,「方針」通りの実装に直すことはできた? →その結果の動作としては,計算時間を除いては問題なく動くところまで行きついた? 「どこかにある解説をパクればACだから,もうそれで」とかいう話では読み手にとっては無価値ですし.
yuki23

2020/05/28 03:01

最低限、ベストアンサーは寄せられた回答の中から解決に最も役に立ったと思われるものを選んでください。私だけでなく、fanaさん、nnenn0さんも善意から時間を割いて回答しておりますので。 目の前のコードを直してほしいのではなく、TLEにならない方針まで考えてほしい、と読み取れなかったのは、私にも落ち度があったことは認めます。
fana

2020/05/28 03:12

元々は > テストケース1は通りましたが、2は通りませんでした。 ということで,「TLEがどうの」というのは当初の問題が解消された後から新しく出てきた(全く別の)話だと見えます. なので, > 計算時間を除いては問題なく動くところまで行きついた のであれば,そこがひとまずの着地点であろうと個人的に考えます.
shibahama

2020/05/28 11:57

>fanaさん 今回は、自分が考えた方針が合っているのか、又は合っているが実装に不備があるのか、自分の稚拙さも故に分からない状態で、とても曖昧な質問をしてしまいました。申し訳ないです。 とりあえずコードのバグを指摘してもらい、自分の立てた方針通りの実装が出来たので、この問題は解説の手法を吸収して次に活かすという方向で行こうと思っています。 >yupi23さん 仰る通り、お時間を割いて回答くださった皆さんからBAを選ぶべきですね。自己解決回答をもう少し充実させた上で、yupi23さんにご指摘いただいたことでコードが改善されたことは事実なのですが、プログラミングに対する姿勢について深く考えさせて頂いたfanaさんを改めてBAとして選ばせていただきます。御二方ともありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問