No.681 Fractal Gravity Glue - yukicoder
解法
頑張って解いたので解法を書きます。
まず、以下の関数を定義します。
の段数を返す
段目までの石の大きさの総和を返す
の石の大きさの総和を返す
実装の都合上、 の引数には を満たす最も小さな も含め、
のように呼び出すことにします。
を から順に増やしていき、 が成り立ったら を出力する、という方針で解きます。 以下、各関数の実装です。
この関数では、 の値はそれほど大きくならないので、定義通りの再帰関数を書きます。
long long count(long long i,long long d) { if(i<1)return 0; else if(i==1)return d; else return d+count(i-1,d)*(d+1); }
とすると、石の塔は と重なります。
したがって、 に の大きさの和を掛けて 、残りを再帰的に として足し合わせれば求まります。
を終了条件として、 を返しておきます。
long long sum_n(long long i,long long d,long long n) { if(n==0)return 0; long long s=count(i-1,d); long long t=n/(1+s); return (t*(i+sum(i-1,d))%mod+sum_n(i-1,d,n-t*(1+s)))%mod; }
と同じように再帰的に求めようにも、この関数については にわたる数が大きくなりすぎる可能性がありますから、そこを何とかする必要があります。 とりあえず、再帰を書いてみます。
long long sum(long long i,long long d) { if(i<1)return 0; else if(i==1)return i*d%mod; else return (i*d%mod+sum(i-1,d)*(d+1))%mod; }
考えてみると、これはforループで以下のように書けます。
long long sum(long long i,long long d) { long long ans=0; for(long long j=1;j<=i;j++) { ans=(j*d%mod+ans*(d+1)%mod)%mod; } return ans; }
さて、分解していくと以下のようになります。
各 について が一回、 が複数回掛けられ、それの総和のようです。
変形して
これなら時間的にも全く問題ありませんね!
long long sum(long long i,long long d) { return((d+1)*(pow(d+1,i)+mod-1)%mod*pow(d,mod-2)%mod-i+mod)%mod; }
これですべての関数が完成し、ACすることができました。 ソースコードの全体を下に載せておきます。
#include<iostream> using namespace std; long long mod=1e9+7; long long count(long long i,long long d) { if(i<1)return 0; else if(i==1)return d; else return d+count(i-1,d)*(d+1); } long long pow(long long a,long long b) { return b?pow(a*a%mod,b/2)*(b%2?a:1)%mod:1; } long long sum(long long i,long long d) { return((d+1)*(pow(d+1,i)+mod-1)%mod*pow(d,mod-2)%mod-i+mod)%mod; } long long sum_n(long long i,long long d,long long n) { if(n==0)return 0; long long s=count(i-1,d); long long t=n/(1+s); return (t*(i+sum(i-1,d))%mod+sum_n(i-1,d,n-t*(1+s)))%mod; } main() { long long n,b,d; cin>>n>>b>>d; for(long long i=1;;i++) { if(count(i,d)>n) { cout<<(sum(b,d)+mod-sum_n(i,d,n))%mod<<endl; return 0; } } }