P3216 [HNOI2011]数学の宿題
...見えたセグメント
kは桁数とします
1--9 - > K = 1
10--99 - > K = 2
100--999-> K = 3
だから、再帰式
F
[N ] = F [1-N ] * ^ 10-N 1 + K(KはNビットの数です)
だから、行列は次のようになります。
10 ^ K | 0 | 0 |
---|---|---|
1 | 1 | 0 |
1 | 1 | 1 |
しかし、行列が長くなる、それを行う方法を、私たちは、別々に処理することができ、最初の行列F [ 0 ] =>(0,0,1)
長さ(n)は1桁までの列挙-1ビット、10K行列乗算は、9 * 10K-1回を有します。
最後に、治療の長さ(n)ビットは、N-Σlength(N)は、k = 1(9 *の10K-1)回の10length(n)の行列を乗算しました。
終了するために、複数の時間を過ごし、40を支払います...
ULLの定義を見つけるために、2時間だけ調整し、scanfの%D .................皿の中のヒットとなりました
だから、デベロッパーからの警告の最大の過ちを開きました...
AC码
書式#include <cstdioを>
する#include <CStringの>
書式#include <アルゴリズム> に#define ULL符号なしの長い長い 使用して 名前空間はstdを、 ULL N、M、PO [ 25 ]、LIM [ 25 ]。 構造体MAT { ULL [ 3 ] [ 3 ]。 MAT(){memsetの(0、はsizeof A);} } TRAN、ANS。 ボイドプレ() { tran.a [ 0 ] [ 1 ] = 1、tran.a [ 0 ] [ 2 ] = 1 ; tran.a [ 1 ] [ 0 ] =0、tran.a [ 1 ] [ 1 ] = 1、tran.a [ 1 ] [ 2 ] = 1 ; tran.a [ 2 ] [ 0 ] = 0、tran.a [ 2 ] [ 1 ] = 0、tran.a [ 2 ] [ 2 ] = 1 ; PO [ 0 ] = 0、POは、[ 1 ] = 1 。 以下のために(int型 I = 2、iは<= 19 ; I ++ ) { PO [I]= PO [I- 1 ] * 10 。 } [貼り付け0 ] = 1 。 以下のために(int型 i = 1 ; iは= < 18 ; iは++ ) { 貼り[i]は =ペースト[I- 1 ] * 10 。 } [貼り付け0 ] = 2 ; ans.a [ 0 ] [ 0 ] = 1、ans.a [ 1 ] [ 0 ] = 1、ans.a [ 2 ] [ 0 ] = 1 ; } MATのMUL(MAT U、MATのV) { MAT Wを、 int型I、J、K。 用(i = 0 ; iは< 3 ; iは++ ) のための(j = 0 ; J < 3 ; J ++ ) のための(K = 0 ; K < 3 ; kは++ ) (WA [I] [J] + = UA [I] [K] * VA [K] [J])%= M。 リターン・ワット。 } MATのPOW(MATのB、ULL P) { 場合(P == 1)リターンB。 MATさt = POW(B、P / 2 )。 Tの =MUL(T、T)。 リターンのp%2 == 0?T:MUL(T、B)。 } int型のmain() { scanf関数(" %のLLDの%のLLD "、&N、&M)、プレ()。 以下のために(int型 i = 1 ; iは= < 18 I ++; ) { 場合(LIM [I- 1 ] <= N) { tran.a [ 0 ] [ 0 ] = PO [iが+ 1 ]%のM。 あれば(私は< 18 && [I] LIM - 1<= N)ANS = MUL(POW(TRAN、LIM [I] -lim [I- 1 ])、ANS)。 そう であれば(LIM [I]> N)ANS = MUL(POW(TRAN、N-LIM [I- 1 ] + 1 )、ANS)。 } 他に ブレーク。 } のprintf(" %LLDする\ n "、ans.a [ 0 ] [ 0 ])。 リターン 0 ; }
2019年7月30日午後12時57分02秒
コードはまだ明らかではない何かである、明日書きます