メルペイのGWポイント還元で最大限得する方法（遊び）

##メルペイとそのGWキャンペーン
皆さん、メルペイはご存知でしょうか。
メルペイとは、メルカリのスマホ決済サービスのことです。
このGW中（4/26(金)～5/6(月)）に、メルペイでは、「ニッポンのゴールデンウィークまるっと半額ポイント還元！キャンペーン」を行っています。
このキャンペーンでは、メルペイ加盟店でメルペイを利用して決済すると、
支払いの翌日に支払額の50%相当（セブン-イレブン店頭での支払いの場合は70%相当）がポイント還元されます。
ただし、キャンペーン期間を通じて計P2,500が上限となっています。

ここで気づくべきところは、ポイント還元で得たポイントをさらにメルペイの決済に回せるというところです。つまり、（50%なら）5000円分投入しなくても、P2500がゲットできるのです。

如何に最大限の効率でP2500を回収するか、言い換えれば、如何に投入額を抑えて、P2500を得ることができるかを考えてみます。
それには、**初日以外は、ポイント還元で得られたポイントで、決済を進めるのが良さそうです。**

##ポイント還元で得られたポイントで決済を進める⇒等比級数モデル
初日投入金額を$a_0$として還元率をPとしたとき、M+1日目には$a_0 p^M$のバックが得られます（セブンと他の加盟店を混ぜないことで簡単な話にしました）。

この形、もちろん見覚えありますよね？
そうです、等比級数の一般項です。
この等比級数の初項（初日投入金額）以外のM+1日目までの和が2500円になると考え、初日投入金額を求める式を導くと、

 $$a_0 = 2500 \times  \frac{1-p}{p} \times \frac{1}{1-p^M}$$

となります。
$a_0$はPとMの関数であることが見て取れますが、Pは0.5 or 0.7であるので、結局Mのみの関数であることがわかります。このMを、以降、回収期間と呼ぶことにします。

じゃあ、回収期間Mを決めて、つまり、どれぐらいの日数でポイントを回収したいかを決めて、初回投入金額を求めれば終わりじゃん～。
ということには、実はなりません。
初出の事実になりますが、還元されるポイントは、決済額に還元率をかけたものの小数点以下を切り捨てることで決まり、1円以下のバックは0円になるためです。これを0円還元とでも呼びましょう。

そこで、一番小額なM+1日目の還元額が、次の式を満たすかどうかをチェックする必要がでてきます。

$$ a_0 p^M > 1$$

$a_0$を回収期間Mで表して、Mについてこの不等式を解いても良いのですが、$a_0 p^M$の値をプロットした方が楽だしわかりやすいと思ったので、pythonで計算・プロットしていこうと思います。

##等比級数モデルと課すべき条件についてpythonを用いて調べる

```python

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

p=0.7; Mx=30
c = 2500*(1-p)/p
M = np.arange(1,Mx+1) 
a_0 = c/(1-p**M) #初回投入金額
bp = a_0*(p**M) #M+1日目の還元金額(back point)

bpt = np.array([]) #総還元額
for mx in range(1,Mx+1):
    
    s=0; a = c/(1-p**mx)
    for n in range(1,mx+1):
        a=a*p
        if a>=1:
            a=int(a) #還元時の切り捨て
            s=s+a
        else:# P1を切る場合
            print(mx) 
            break
        
    bpt = np.append(bpt,s)

plt.figure(figsize=(16,4))

plt.subplot(1,3,1)

plt.plot(M,a_0)

plt.subplot(1,3,2)
plt.plot(M,bp)
plt.ylim(0,1)

plt.subplot(1,3,3)
plt.plot(M,bpt)
# plt.ylim(2499,2501)

```

![0.7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378787/5ac40958-cff1-a2b6-25f9-5941379f1a8f.png)
(キャプション・軸名等は時間がある時に加えます。)


このコード・実行結果は、70%還元（セブン）の場合に、回収期間Mを変化させたものとなっています。

左の画像は、回収期間Mに対する$a_0$のプロットです。双曲線を描き、Mが大きくなるほど1000円に漸近していきます。P2500を得るのに、単に0.7で2500を割った値を投入しなくてもよく、Mが長ければ、1000円程度の投入で十分なのです。

中央の画像は、気になっていた$a_0 p^M$のプロットです。回収期間Mが長くなると、還元額が1円を切ってしまっています。M=20を超えると、途中からポイント還元がなされず、P2500に達しないことになります。

この2つから、**1円以下の還元額のみ切り捨て処理を考慮した場合**、M=19（計20日)で初日だけ1073円のお金を払えば、最大効率でP2500が手に入ると言えます。
ここでわざわざ強調した理由は、毎度毎度行われている切り捨て処理に関して、上2つの結果は考慮していないからです。

そこで、初項を求めるときを除いて切り捨て処理を考慮した際に、想定している回収期間M中での総還元額を求めた結果を右の画像に示します。
M=1以外はP2500に到達せず、M=18以降からは一定値を取っています。段々と総還元額が減っていくのは、初回投入金額$a_0$を決める際に、切り捨て処理を考慮せず、等比級数の和から求めていることに起因します。切り捨て処理をしているので、M+1日間(1日目除く)の等比級数の和より小さく求まるのは当たり前です。また、M=18以降で一定値を取るのは、途中から0円還元が始まるからです。
この結果からわかることは、初回投入金額$a_0$の大きさで回収期間中に0円還元が始まるかどうかが決まり、もし0円還元が始まると一定値2475円を取るということです。一定値を取っていないところは、回収期間Mを超えてポイント還元を楽しめば、合計でP2500回収できるかもしれません。

##まとめ・更なる解析
###まとめ
ポイント還元で得られたポイントで決済を繰り返し行っていく等比級数モデルを立て、課すべき条件を考え、pythonで解析を行いました。
0円還元以外の切り捨て処理を考慮せず、回収期間Mを設定することで、最小初日投入金額$a_0$を求めると、M=19で$a_0$=1073 円となりました。
毎度毎度の切り捨て処理を考慮すると、回収期間Mから見積もった$a_0$では、M=1以外は回収期間中にP2500に到達できないことも（当たり前のことだが）図示できました。

###更なる解析
この記事を書きながら考えたので実行してはいませんが、最大効率でP2500を得るための初回投入金額を正確に決定する方法には、次のものがあると思います。
初期投入金額を振りながら（for文）、切り捨て処理をしたうえで（intへのキャスト）、P2500に到達するまで回収していく（while文）とかでプログラムを書いて求める方法です。ただし、0円還元の際にwhile文をちゃんと抜け出せるよう注意が必要だと思います笑
興味がある方は、やってみてください。
読んでいただきありがとうございました。

以上