tsugaru’s blog

主に技術的なことをつぶやきます。プログラミング,ポケモンGO,音楽,アニメ等

ABC310 Eの解き方

落ちているやり方と違っていたので

仮にf(i,j)が一瞬でわかったとして、長さは106であるから、 f(i,j)の全ての通りを足す時間(1012)はない。

ここで、例えばあるiについて  \sum_i f(i,j) = g(j) がすでにわかっていたとする。 このとき、g(i-1)との間に何か関係があれば、 106に対して2乗しないで済み、他のg(i)を定数で求められるので、合計が106で求まる。

ここで、

 \sum_{i=1}^{N} \sum_{j=i}^{N} f(i,j) = \sum_{j=0}^{N} \sum_{i=1}^{j} f(i,j)

である。


\begin{align}
g(j) &= \sum_{i=1}^{j} f(i,j) \\
g(j+1) &= \sum_{i=1}^{j+1} f(i,j+1) \\
           &= \sum_{i=1}^{j}f(i,j+1) + f(j+1,j+1) \\
            &=  \sum_{i=1}^{j} f(i,j)nand A_{j+1} + A_{j+1}
\end{align}

ここで、 x \ nand \ y = 1 - xyであるから、


\begin{align}
g(i+1) &= \sum_{i=1}^{j} (1-f(i,j)*A_{j+1}) + A_{j+1} \\
       &= j-A_{j+1}*\sum_{i=1}^{j}f(i,j) + A_{j+1} \\
      &= j-A_{j+1}*g(j) + A_{j+1}
\end{align}

以上を用いて作成したプログラムは以下の通り。

n=int(input())
s=input()
g_old=int(s[0])
r=g_old
for j in range(1,n):
    g_old=j-int(s[j])*g_old + int(s[j])
    r+=g_old
print(r)

スウィングガールズを見た。この高揚感は何だろう。

私はクラシック音楽のサックス吹きを趣味でしているのだが、ジャズはなかなか触れられない領域であった。ジャズによって自分の好きなクラシックサックスの音色に影響が出るのを心配していたのが一番大きい部分である。とはいってもジャズが嫌いなわけではない。むしろ、どういうものかと探索こそしていないのであったが、「覗いてみたさ」みたいなものをずっと持っていたわけである。

それも相まって以前からスゥイングガールズを見たいと思っていた。さらに先日、IN THE MODEを演奏する機会を得て、私の吹き方はどうもクラシックであると指摘を受け、「スゥイングガールズ今の人は知らないかぁ」とお言葉を頂いた。別に負の感情というわけではないのだが、「なにこのっ!」と、思わなかった訳ではない。視聴意欲がピークに達した私は、現状Amazon Prime Video などの配信がないことを確認し、これを借りるためにXSUXAXAの会員となったわけである。

以下はネタバレを盛大に行います。ご理解ください。

もっぱらドラマなど見ない私ではあるのだが、少々古めかしい雰囲気漂うこのアットホームな感じの雰囲気の演出は、非常に良い印象を受けた。舞台が東北地方であるのも非常に良かった。スゥイングガールズは、監督が女子高校生のビッグバンドに感銘を受け作成を決め、様々な候補地の中から東北を選び、「ジャズはおっさんがやるもんだ」といったセリフも東北弁で彼女らがいうから辛辣なコメントもオブラートになる、と言っていたのだが、なるほど、大正解といってよいだろう。私は東北地方は何度か1週間程度の一人ないし二人旅に行ったのだが、電車の走る光景、雪の積もる光景、のどかな風景を映像でみて旅行を思い出したと同時に、また行きたくなったのである。

また、演技、演出の部分もよかった。幾度となくギャグを挟み、コミカルな印象であったのだが、そこには脚本としての面白さと演者たちの表情変化、動作の豊かさ、掛け合いが理由としてあったのは間違いないだろう。

さて、肝心の音楽に絡めた部分について言及しようと思う。

まず、最初の楽器の存外な扱われ方は心を痛めずにはいられなかった。「あなたが手放したくないものを一つ選べ」と言われたら、楽器を真っ先に答える自分にとって、演出であってもそのような扱われかたとなるのはどうしても心が痛んでしまう。だが、振り返るとそこまでやってくれてこそ彼女らのキャラ付けと音楽への熱中、楽しさ、変化が伝わるのであって、否定できるものではないと思った。中古の楽器について、お金持ちの人が中古の悪い部分を表明し、実際不具合が多くあった場面がある一方で、修理して最後まで使っていたのは非常に良かった。楽器は非常に高価なものである一方で、お金がない人から音楽をやる権利を奪ってはいけないのである。修理も楽器屋ではなくその辺の町工場みたいなのもそういう意味でよかった。初期メンバー以外の人は新品の楽器を買っていた。スポンサーの関係もあるのかもしれないが、メインキャラクターの際立たせの意味や、新品楽器の存在をちゃんとアピールしているあたりでバランスもよかったと思う。

練習風景については体育会系の練習で少々見ていて苦い思いがした。あくまで自分の考えではあるのだが、持久走、腹筋やブレストレーニングといったものは、楽器を手放してやるより、楽器を使ったロングトーンなどの練習のほうが良いと思う。映画であるのでパフォーマンス的意味合いであろうが、この辺のイメージは令和の時代には変わってほしいとは思う。

吹奏楽部は優遇されていていいなぁ、という部分は、自分は当事者ではあったのだが、確かに周りから見たらそう見えるなと思うと現実的で素直な感想だと思った。

スーパーの前での演奏が、初期メンバー数名の演奏を聴いてビッグバンドになるシーンがあったのだが、そこが非常に良かった。少ない人数でも音楽はできるが、そのあたりで明らかに音楽の色が豊かになってよりゴージャスでわくわくした演奏になったのは、まさに「音楽は大勢でやると楽しい」、ということを体現しているようで、見事だと思った。

彼女らはみなこのドラマをとるために楽器を練習しはじめたようだが、吹替なしにしたことでリアリティーが増し、音楽は誰でも楽しめることを示してくれたように思う。「響けユーフォニアム」というアニメにおいて、入学式演奏が絶妙に下手であり、そのリアルティーさに惹かれたのだが、それに似たものを感じた。とはいっても私はジャズの上手さはよくわからないのではあるが。

ドラムソロなど、シンプルでおそらく初心者向きのものであったのだが、それを感じさせないカッコよさがあった。最後の10分は演奏をしているのであるが、私は高揚のあまりリズムを感じながらハチャメチャに踊りながら見ていた。また、トランペットの人は音が整っていて、金管楽器のできない私からしたらすごいと思ったのである。

私は音楽は本人が楽しければ何をやってもよい、とは思っていない。が、技術力がどうであれ、演奏者とパッションを共有できたと感じれたこの演奏、演出は、まさに音楽の一体感的良さであるし、このように感じたことを大切にしたいと思た。

私にとってスゥイングガールズは、「音楽とは(音楽の楽しみ)」をストーリーではなく、表情、しぐさ、音楽で伝えてくれる映画であった。気分を前向きにしたいときに再度見たいと思えるような映画であった。

シリアス展開やねちっこい展開がなく、明るく、楽しくなる。 ぜひ、ライブに行くような気持ちで楽しんで見てほしい。

追記 スウィングガールズチームがお客さんのためにツアーを行っていたのだが、そのDVD(スウィングガールズ・ファースト&ラストコンサート)も借りた。 コンサートの中で監督が、彼女らが演技なしで心から楽しそうだったのでうらやましくなりサックスを始めた、というエピソードを聞いたとき、音楽っていいな、いい製作チームだったんだなぁと思ったのだった。 こちらも借りておいてよかった。本編が良かったと思った方はぜひこちらも見てみてほしい。 世代じゃなかったので知らなかったが、当時彼女らはまさに青春真っただ中の年であり、そういった意味でも 真のドキュメンタリー的な雰囲気を感じた。学生時代の最後の定期演奏会を思い出さずにはいられなかった。

Windows版Magic TrackpadでうわさのW-Touchを買ってみたのでMacbook Airと比較してみた

WindowsPCを購入するにあたり、今まで使っていたMacのようなTrackpadはないものかと調べていると、Brydgeが販売するW-Touchに行き着いた。本記事はアフェリエイトを目的としていない純粋なレビューです。この商品に関しては優れているものの否定的立場をとります。

詳細は公式サイトを見てほしい。 検証OSはWindows 10 Home。 比較先は、私の使用しているMacBook Air(Retina,13inch,2020)(OS : macOS Big Sur 11.3.1)を使う。

概要

公式サイトの引用ではあるが、おおむねの概要を以下に示す。

項目 内容 補足
互換性 MicrosoftSurfaceまたはWindows10ラップトップ
サイズ 横:140mm 縦:84mm 高さ:11mm(最も高い点) サイズ感はMacBookAirのTrackpadよりやや横に大きい程度で第一印象は思ったより小さい。
重量 160g 持つと見た目通りのイメージの重さ
モデル番号 BRY2303
接続 Bluetooth4.2、USB-C(充電中)
バッテリー 最大1 カ月 検証していません
素材 アルミニウム
内容物 本体、日本語対応マニュアル、USB-C-USB-Cケーブル 変換アダプタは入ってなかった

以上が公式の和訳とその項目についての私からのコメントとなる。

そのほか公式情報と使用感をもとに文章でお伝えする。

タッチパッドでできること

インターフェースについて、4本までの操作が可能。

これらはWindowsの設定>デバイス>タッチパッドで設定ができ、設定項目として、

  • カーソル速度
  • 2本指クリックをマウスの右クリックと対応させるかどうか
  • トラックパッドの右下あたりを押すと右クリックと対応させるかどうか
  • 2本指でドラッグとスクロールの対応をさせるか、およびその方向
  • ピンチ操作によるズームをするか
  • 3本指ジェスチャについて、4方向のスワイプ操作を何と対応させるか
  • 3本指ジェスチャについて、4方向のスワイプ操作を何と対応させるか

がある。 3,4本指のスワイプ設定は、デフォルトでは、Macと同じようなイメージ操作ができる。 ただし、左右でデスクトップを切り替えるときの方向が真逆。スワイプ設定の概要は変更できるが、 方向の意味付けなどの詳細設定はWindowsの設定項目では厳しそうだ。 ただ、2本指でスクロールはなぜかMacと同じ方向がデフォルトで設定されていた。

私がよくMacで使っていた機能として、

  • 1本指クリック
  • 2本指スクロール
  • 2本指クリック
  • 2本指横スワイプでブラウザバック。
  • 3(4)本指でWindow切り替え

があるが、すべてほぼ同じようにできることを確認。 つまり、おおよそMacと同じ操作ができると期待できます。

形状、操作性について

形状は手前に向かって緩やかに傾斜する形をしており、クリック感は奥に基点のある感じの板が実際に回転するイメージで 実装されている。そのため、手前ほどそのストロークが長く、軽いクリックが可能であるが、奥になるほど重く、動きは小さくなり、奥1/3については、押すのが不可能と思ってよいだろう。MacのMagicTrackpadはどこでクリックしても同じ圧力で比較的軽めの圧で操作が可能だったため、同じような操作をしようとするとストレスがたまる。 また、そのような設計のためか、クリックは非常に重い。最も軽く押せる手前ですら、MacBookAirと比較して体感2倍はある。つまり、同じ感覚で操作していたらクリックすらできない。これで長時間使うとなると指がつかれることは間違いないであろう。MacBookではマウスが不要であったが、こちらを使う場合にはマウスが必須と思われる。

購入、価格

国内サイトで一部取り扱いがあったが、アメリカ版アマゾン(amazon.com)のほうが2021年8月末の購入当初は安かった。 本体価格が79.99ドル(公式価格通り)、手数料、送料で10ドル程度で当時の日本円にしてトータル1万円程度で購入ができた。 ただ、同年9月の執筆時点において、品切れのようである。もし在庫が復活したらぜひamazonでもレビューを見てほしい。 評価はおおむね高いのであるが、低めな評価については、Macユーザーと思われる人からのコメントが多い印象である。

まとめ

MacBookと同じ操作性をWindowsとW-Touchで検証したところ、操作方法はおおむね同じようにできるが、 クリックの場所ごと違いおよびクリックの重さがネックになっている。 そのため、使うのであればマウスとの併用が望ましい。

最後に実物のレビューについてはどなたかが日本語でYoutubeに挙げているので調べてみてください。

Unity MonoBehaviourのコンストラクタとPrefabの関係

Object.Instantiateについて色々調べていた。 ここで、生成元のObject originalについて、インスタンス化される前のPrefabのGameObjectを指定できるのに違和感を覚えた。 というよりは、[SerializedField] GameObject prefab;の違和感である。 プレファブが実態となっていないのに、GameObject型のインスタンス変数としてプレファブを指定できるのは、どういうことだとなったわけだ。

そこで、Monobehaviourでは、インスタンス化はAddComponentによって行う、という点を思い出し、コンストラクタを加えてみた。

using UnityEngine;

public class PrefabTest : MonoBehaviour
{
    static int num = 0;
    PrefabTest()
    {
        Debug.Log("Constructor:" + num);
    }

    private void Awake()
    {
        num++;
        Debug.Log("Awake:" + num);
    }
    void Start()
    {
        Debug.Log("Start:"+num);
    }

}

これをつけたオブジェクトをプレファブにしてシーンから取り除く。 その後、シーン上のスクリプトでプレファブへの参照をインスペクタービューで登録した瞬間(エディタの使用中) Constructor:0と表示された。 また、再生を押すと、Instantiateが使われていないのに、Constructor:0と表示された。

これらから、Unityにおいて、GameObjectのインスタンス化は、エディタ上でも、実行中でも、シーンからの参照があった時点で行われることがわかった。 また、インスタンス化されても実際にシーンに設置されないことがある(Awakeなどが呼ばれない)(これはプレファブの参照元ぐらいしかなさそうだが)ということがわかった。つまり、Unityにおける「GameObjectのインスタンス化」と実際の「GameObjectクラスからインスタンスが作成」されるのでは、微妙に意味が異なることがわかった。

UnityのInputFieldの日本語入力について

環境:Unity 2018.3.11f1 ,Mac OS:Big Sur 11.3.1

UnityのInputField.textを取得する際、日本語入力だとうまくいかない。 他のブログでは LintTypeをMultiple Line NewLine にして改行コードを取り除くとあるが、どうも不自然な実装に感じる。

入力されたコンポーネントであるTextコンポーネントからはどうやら通常通り取得できるようである(Unity Editor上の実行では)。 そのため、 inputField.textComponent.textで私は取得することにした。 これが先例や他の方法と比べ良い解決策かは分かりませんがもっとも直感的で齟齬がなさそうなので採用しました。

unityにおけるTPS風移動、カメラ移動の実装(Caracter Controllerを使用)

Unityはまだ慣れていませんので、参考程度にしてください。

Character Controllerを用いて以下のように実装しました。 詳しくは以下のコード中に書いてあります。

using System.Collections;
using UnityEngine;

/*
 * 構成図
 * root [このスクリプト、CharacterControll、Animator]
 *  |- Camera
 *  |- Initial Camera Transform [からのオブジェクト]
 *  |- Rotate Body[主に カメラ基準にした時の回転方向。からのオブジェクト。しばしばモデルそのもののルート]
 *      |- モデルの構造体
 *      
 * マウスの左右でカメラ視点切り替え
 * 十字キーでカメラ視点方向を基準に8方向に動く
 * character controllerを用いるため、超えられる段差の調整はそちらで行う
 * character controllerを用いるため、rigidbodyなどは基本使わない
 * 体がカメラ視点方向を基準とするタイミングはなんらかの十字キーを押したタイミング
 * カメラはキャラクターの上下移動に対し、画角の基準になるまでは動かない
 * ジャンプ中も移動が可能
 * キックアクション中は地上にいる時移動が止まるが、ジャンプ中は移動できる(大技に改造できそう)
 * animationは各自自由に設定する
 * 
 * 未実装など
 * カメラの上下回転移動
 * カメラ基準にモデルが戻る時の回転のスムースと、モデルが180度方向が変わる時のスムース
 * カメラ移動のキャラクターに対するスムース
 */

public class PlayerController : MonoBehaviour
{
    CharacterController controller;
    Animator animator;
    [SerializeField] float walkSpeed=2;
    [SerializeField] float runSpeed = 5;
    [SerializeField] float accel = 5;
    [SerializeField] float blake = 10;
    [SerializeField] float maxAngle = 45;
    [SerializeField] Transform rotateBody;
    [SerializeField] float cameraRotateSpeed=10;
    [SerializeField] Transform playerCamera;
    [SerializeField] Transform initialCameraPos;
    [SerializeField] [Tooltip("ジャンプの初速度")]
    float jumpVelocity = 13.5f;
    float rotateAngle = 0;
    float verticalVelocity = 0;
    float oldCameraY;
    bool canMove = true;//地面に触れている時、falseなら入力を受け付けない

    [SerializeField,Header("Not Changeable.For Debug")]float speed=0;
    void Awake()
    {
        controller = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
        oldCameraY = playerCamera.localPosition.y;
    }
    IEnumerator Kick()
    {
        canMove = false;
        animator.SetTrigger("Kick");
        yield return new WaitForSeconds(0.5f);
        canMove = true;
    }

    void Update()
    {
        CameraMove();
        Move();
        CameraHeight();
        if (Input.GetKeyDown(KeyCode.Mouse0)&&canMove)
        {
            StartCoroutine(Kick());
        }   
    }
    void CameraMove()
    {
        float h = Input.GetAxis("Mouse X");
        playerCamera.RotateAround(transform.position, Vector3.up, h * cameraRotateSpeed);
        if (Input.GetKeyDown(KeyCode.Z))
        {
            //キャラクターの前の方向にカメラの方向を合わせる
            // todo
            //transform.localRotation=
        }
        oldCameraY=playerCamera.position.y;
    }

    void CameraHeight()
    {

        //上下でプレイヤーが画伯から出そうになるまでカメラは動かない
        Vector3 pos = playerCamera.position;
        Vector3 oldPos = pos;
        pos.y = oldCameraY;
        playerCamera.position = pos;

        Vector3 p = Camera.main.WorldToViewportPoint(transform.position);
        if ( p.y<0 || 0.25f <p.y)
        {
            // 画伯からはみ出た、もしくは画伯に入ろうとしているとき
            //カメラの高さはプレイヤーの動きに付随する
            playerCamera.position = oldPos;
        }
    }
    private void Move()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        if (!canMove&&controller.isGrounded)
        {
            // ジャンプ中のキックは、移動しながらのアクションを認める
            x = 0;z = 0;
        }
        float magnitute = x * x + z * z;
 
        if (magnitute != 0)
        {
            //Debug.Log("move x:"+x+"z:"+z);
            //動いたら全体をカメラの方向に向け、カメラの位置をリセットする。
            Vector3 bodyAngle = transform.localEulerAngles;
            bodyAngle.y += playerCamera.localEulerAngles.y;
            transform.localEulerAngles = bodyAngle;

            // yは回転に関与していないのでリセットしない。
            Vector3 pos = playerCamera.position;
            pos.x = initialCameraPos.position.x;
            pos.z = initialCameraPos.position.z;
            playerCamera.position = pos;
            playerCamera.rotation = initialCameraPos.rotation;

            
            if (Input.GetKey(KeyCode.LeftShift))
            {
                // シフトキーを押して加速する時
                speed += accel * Time.deltaTime;
                speed = Mathf.Clamp(speed, 0, runSpeed);
            }
            else if (speed <= walkSpeed)
            {
                // 歩くスピードまで加速する時
                speed += accel * Time.deltaTime;
                speed = Mathf.Clamp(speed, 0, walkSpeed);
            }
            else
            {
                //歩くスピードを超えて走っていて減速する時
                speed -= blake * Time.deltaTime;
                speed = Mathf.Clamp(speed, 0, runSpeed);
            }
            rotateAngle = Mathf.Clamp(Mathf.Atan2(x, z), -maxAngle, maxAngle);           
        }
        else if(speed>0)
        {
            // 何も押していない時
            speed -= blake * Time.deltaTime;
            speed = Mathf.Clamp(speed, 0, runSpeed);
        }

        rotateBody.localEulerAngles = new Vector3(0, rotateAngle, 0) * Mathf.Rad2Deg;
        animator.SetFloat("Speed", speed);
        Vector3 move = transform.rotation * new Vector3(x, 0, z) * speed;


        if (controller.isGrounded)
        { 
            verticalVelocity = 0;
            if (Input.GetKeyDown(KeyCode.Space))
            {
                verticalVelocity += jumpVelocity;
                animator.SetTrigger("Jump");
            }
        }
        else
        {
            animator.SetFloat("Speed", 0);
            //地面についていないときは加速を続ける
            verticalVelocity += Physics.gravity.y*Time.deltaTime;
            verticalVelocity = Mathf.Clamp(verticalVelocity, 0, jumpVelocity);
        }
        
        move.y = verticalVelocity;
        controller.Move((move+ Physics.gravity)* Time.deltaTime);
    }
   
}

f:id:pika-bika:20210519142600p:plain
アニメーション
f:id:pika-bika:20210519142604p:plain
歩行などのブレンドツリー

Unityにおけるシーン遷移についてのメモ

Unityは初心者です。 自分のメモのため、シーン遷移について残しておきます。本来は公式ドキュメントをリンクとすべきですが、サボっています。

UnityにおいてSceneManager.LoadSceneをすると、デフォルトのモードがLoadSceneMode.Singleのため、遷移前のシーンの全てのオブジェクトは破棄されます。遷移後のシーンは毎度新しくインスタンスが作成されます。 そのため、値を保持する時、工夫が必要です。複数調べたのでまとめます。 一口にデータ保存と言っても、そのデータの特性からよりよい実装が異なると考えられます。

静的フィールドによる保持

よーく考えてから使うべき。

シングルトンパターンの使用

Managerオブジェクト的なものを用意してそのオブジェクトをDontDestroyOnLoadする。するとシーン遷移が怒ってもそのオブジェクトは破棄されない。元のシーンに戻ってくると、このオブジェクトのインスタンスが再生成されてしまう。そこで、初めてインスタンスが生成された時、そのインスタンスの参照をstaticで持つことで、複数生成を防ぐロジックを作成する。これは結局シングルトンパターンの実装方法となる。 https://gametukurikata.com/basic/scriptableobject https://gametukurikata.com/program/scriptableobjectitemdatabase

シーンを上書きするような方法

あまりなさそうだが、LoadSceneでSimpleでなくAddモードで行う。これは元のシーンの全オブジェクトを非アクティブにすれば良さそうだが、、、メモリが無駄。

PlayerPresで保存する

これはUnityを終了しても保持される。セーブ機能として使われる領域。 https://gametukurikata.com/program/data

ScriptableObjectを継承したインスタンスの使用

このスクリプトを作ると、Monobehaviourと異なり、アセットとしてインスタンスを作成する。ただし、インスタンスの作成についてはUnityのシリアライズ機構を経由するためにnewではなく、ScriptableObject.CreateInstanceで作成する。アセットとして保存するにはAssetDatabase.CreateAssetを用いて、拡張子に.assetsを指定する。簡単に行うには、CreateAssetMenu属性を使う。 Scriptableインスタンスへの参照を何らかの方法で取得することにより、シーンで使うことが可能。方法としては、.assetsファイルの参照(インスタンスの参照)をSerializedFieldを用いて渡したり、AssetDatabase.LoadAssetAtPathでロードする方法がある。 49.233.81.186

ロードのタイミングで前のシーンのデータを次のシーンに渡すイベント関数を使用する

SceneManagerのSceneLoadedにイベント関数を追加(引数はnextScene,LoadSceneMode)して、そこで次のシーンのインスタンスに今のシーンで渡したい値を渡すイベント関数を記述する

https://note.com/suzukijohnp/n/n050aa20a12f1