【AtCoderBeginnerContest045 C】この体にも慣れてきたな

スポンサードリンク

こんにちは。



コンテストではC# だけではなくC++も使うことを心に決めてから、早いもので5週間ばかりが経とうとしています。



今日はC++でC問題に挑戦しましたので、現状報告とともに問題点を洗い出します。


ABC061 C


https://atcoder.jp/contests/abc045/tasks/arc061_a

問題概要

1,2,3,4,5,6,7,8,9からなる数字の羅列Sが与えられる。

+記号を間にいくつか挟むことを考える。(0でもよい)

+記号の入れ方はたくさんあるけど、全パターンの入れ方を試す。

できる数列全部計算して出てきた数字の和を求めよ。





Sの長さは最大10だそうです。






考えたこと


一瞬、どの桁まで見て計算した、というDPを書こうとしたけど思いとどまった。



最悪数字が10個ってことは、数字の間は9個。

2^9=512パターンなので、多分割と余裕で全探索ができる。



n番目の数字とn+1番目の数字の間に+記号を入れるかどうかをplus[n]が1か0かで決めて、全部試して全部足しました。

plusの次の状態を求める関数、plusとSから数式をstringで出力する関数、+入りの数式を計算してくれる関数を定義して、じゅんぐりにまわしました。


#include <iostream>

#include <string>
#include <algorithm>
#include <list>
#include <vector>
#include <map>
using namespace std;

string addplus(string, string);

long long calc(string);

string next(string);


int main()
{
\t//S=1なら1個、S=2なら2個、S=nなら、各数字の間に入れる入れないがあるので2^(n-1)個。

\tstring S;
\tcin >> S;
\tint veclen = S.length()-1;
\tstring plus = "";
\tstring last = "";
\tfor (int i = 0; i < veclen; i++)
\t{
\t\tplus += "0";
\t\tlast += "1";
\t}
\tlong long output;
\toutput = 0;
\twhile (plus != last)
\t{
\t\tstring next_siki = addplus(S, plus);
\t\toutput += calc(next_siki);
\t\tplus = next(plus);
\t}
\toutput += calc(addplus(S, plus));
\tcout << output << endl;
\treturn 0;
}

string next(string s)
{
\tstring output = s;
\tint keta = '1';
\tint zero = '0';
\tint one = '1';
\tint two = '2';
\tfor (int i = s.length() - 1; i != -1; i--)
\t{
\t\tif (s[i] + keta == zero + zero)
\t\t{
\t\t\toutput[i] = '0';
\t\t\tketa = '0';
\t\t}
\t\tif (s[i] + keta == zero + one)
\t\t{
\t\t\toutput[i] = '1';
\t\t\tketa = '0';
\t\t}
\t\tif (s[i] + keta == one + one)
\t\t{
\t\t\toutput[i] = '0';
\t\t\tketa = '1';
\t\t}

\t}
\treturn output;

}

long long calc(string s)
{
\tlong long output = 0;
\tlong long lookingnumber = 0;
\tfor (int i = 0; i < s.length(); i++)
\t{
\t\tif (s[i] != '+')
\t\t{
\t\t\tlookingnumber *= 10;
\t\t\tlong long keta = s[i]-'1'+1;
\t\t\tlookingnumber += keta;
\t\t}
\t\telse
\t\t{
\t\t\toutput += lookingnumber;
\t\t\tlookingnumber = 0;
\t\t}
\t}
\toutput += lookingnumber;
\treturn output;
}

string addplus(string s, string plus)
{
\tstring output = s;
\tfor (int i = plus.length() - 1; i != -1; i--)
\t{
\t\tif (plus[i] == '1')
\t\t{
\t\t\toutput = output.substr(0, i+1) + "+" + output.substr(i + 1, output.length()-1);
\t\t}
\t}
\treturn output;

}





C#userから見た問題点が一つ大きく目立ちます。

それは、



「型変換が雑」





使うプリミティブ型データ(言葉の使い方あってる?)としては、long,string,int,char,doubleぐらいでしょうか。

longとintとdouble間の変換はとりあえずおいておくにしても、stringとcharとint間の変換は見過ごせません。

C#なら、

string→charは、s[0]がcharになるし、

char→stringはchar c;に対して string s = ""+c;とすれば変換できる。

int→char、char→intはそんなに使わないから置いといて、

string→intはint.Parse(string)すればよくて、

int→stringはcharと同じくstring s = "" +i;とでもすればよい。



これがC++となるとまったくわからず、

string→charは同じくs[0]でいいんだけど、

charをstringにできない。哀れ。

string→intもわからないからcharにして'1'引いて1足すという悪魔みたいなコード生成してるし、

int→stringは今回使っていないけどこれもわからない。



競技プログラミングに限ったことではないが、これぐらいの型変換はできるようになっておかないといけないのでは。



競プロで一番困るのは、string[n]で表記して取り出したcharをstringに戻せないこと。どうしたもんかなぁ。



…まだ、「C#と同じぐらいデキル」という境地には至れてません。

この辺の未解決変換についてご存知の方いましたら教えてください。

スポンサードリンク