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

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

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

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

解決済

2回答

1002閲覧

累積和を用いて高速化をする

grape_ll

総合スコア83

C

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

0グッド

0クリップ

投稿2020/08/04 08:00

質問内容

AtCoderの過去問を解いていて,答えが一致するが実行時間が制限以内でない判定を受けてしまったので解説を見てみたのですが,
西から i 番目の人がリーダーになった際、向く方向を変える必要のある人は、西から j(j < i) 番
目に並んでいて西を向いている人と、西から j(j > i) 番目に並んでいて東を向いている人です。
ここで、「ある範囲に存在する西 (東) を向いている人の人数」は、累積和を使うと、前処理 O(N)
時間、1 クエリあたり O(N) 時間で求められます。
よって、まず最初に O(N) 時間で累積和を求めておくと、各人について、その人がリーダーに
なった際に向く方向を変える必要のある人の人数を求めることが O(1) 時間ででき、合計 O(N) 時
間で全員分求まります。あとはその中で最小値を求めればよいです。

とあって累積和を使うとうまくいくそうなのですが,どのような実装の仕方をすればいいのか教えていただきたいです.自分で考えたものを以下に載せますが,これが自分的には累積和になっているのではないかと思ってしまっているので,なにが累積和とは違うのか教えていただきたいです.

C

1for(int i=0;i<N;i++){ 2 if(str[i]=='W'){ 3 for(int j=i+1;j<N;j++) count[j]++; 4 } 5 else{ 6 for(int j=0;j<i;j++) count[j]++; 7 } 8 }

問題

コード全体

C

1#include<stdio.h> 2#include<stdlib.h> 3int main(void){ 4 int N; 5 char *str; 6 int *count; 7 int min; 8 scanf("%d",&N); 9 min=N; 10 str=(char *)malloc(sizeof(char)*N); 11 count=(int *)malloc(sizeof(int)*N); 12 scanf("%s",str); 13 //printf("%s\n",str); 14 15 for(int i=0;i<N;i++) count[i]=0; 16 17 for(int i=0;i<N;i++){ 18 if(str[i]=='W'){ 19 for(int j=i+1;j<N;j++) count[j]++; 20 } 21 else{ 22 for(int j=0;j<i;j++) count[j]++; 23 } 24 } 25 26 for(int i=0;i<N;i++){ 27 if(min>count[i]) min=count[i]; 28 } 29 printf("%d\n",min); 30 31 return 0; 32}

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

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

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

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

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

guest

回答2

0

ベストアンサー

なにが累積和とは違うのか

計算量が違います。解説では累積和の計算がO(N)時間で終わることになってますが、そのコードでは二重ループになっているのでO(N^2)かかります。

O(N)で計算するには、すでに計算されてるcount[i - 1]の値を利用して、

count[i] = count[i - 1] + 変化分

とするだけですが、今のコードのように一つの配列で済まそうとするとなかなかややこしいので、自分の実装力と相談してください。


count[i] は[0, i)に含まれる'W'の個数と(i, N)に含まれる'E'の個数の和になるはずです。つまりちょうどi番目の'W'も'E'も含まれてはいけないはずですが、count[0]の時点で0番目の'E'がカウントされてます。これが原因でしょう。

投稿2020/08/04 12:29

編集2020/08/05 03:15
yudedako67

総合スコア2047

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

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

grape_ll

2020/08/05 01:56

解説ありがとうございます. 教えていただいたことをもとにコードを書いて提出してみましたら,時間は圧倒的に早くなって完全にクリアしました.しかし,結果が答えと一致しない問題が半数ほど出てきてしまいました. もしよろしければどこがよくないのか教えていただきたいです. #include<stdio.h> #include<stdlib.h> int main(void){ int N; char *str; int *count; int min; scanf("%d",&N); min=N; str=(char *)malloc(sizeof(char)*N); count=(int *)malloc(sizeof(int)*N); scanf("%s",str); //printf("%s\n",str); for(int i=0;i<N;i++) count[i]=0; for(int i=0;i<N;i++){ if(str[i]=='E') count[0]++; } for(int i=1;i<N;i++){ if(str[i-1]=='W' && str[i]=='E'){ count[i]=count[i-1]; } else if(str[i-1]=='E' && str[i]=='E'){ count[i]=count[i-1]-1; } else if(str[i-1]=='W' && str[i]=='W'){ count[i]=count[i-1]+1; } else if(str[i-1]=='E' && str[i]=='W'){ count[i]=count[i-1]; } } for(int i=0;i<N;i++){ if(min>count[i]) min=count[i]; } printf("%d\n",min); return 0; }
guest

0

e.g.

text

1←西 東→ 20 1 2 3 4 5 6 7 8 9 A B //index 3----------------------- 4W E E E W E E E W W W E //Data 5----------------------- 61 1 1 1 2 2 2 2 3 4 5 5 //Wの累積(西側から) 77 7 6 5 4 4 3 2 1 1 1 1 //Eの累積(東側から)

リーダーのindexが5であるとき,

  • リーダーよりも西にいて,西を向いている者の人数は,Wの累積の[4(=5-1)]の値
  • リーダーよりも東にいて,東を向いている者の人数は,Eの累積の[6(=5+1)]の値

投稿2020/08/05 02:23

fana

総合スコア11658

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問