問題の意味
整数Nが与えられると、次の文字セットのどの程度を決定する文字列に1つの長さによって巡回シフト後に得られたNパリンドローム配列であることができるように、K列の1の間の整数です。いわゆるサイクリックシフトは、、、、そのような「1221」巡回シフトは「1221」とすることができるように、文字列の末尾に(空であってもよい)接頭文字列に4つの「1122」「2112」「2211」であります文字列。$ 10 $ ^ 7 + 9のmodの結果
問題の解決策
これは、$ $ O(n)の$式をプッシュするだけでなく、$ O(SQRT(N))への妄想を最適化するために、ほとんど時間の試験を受けた......
まず、答えに回文文字列の寄与を考慮してください。
セクションLENの最小サイクル長ことを条件とします。
その貢献はLENです。
しかし、回文文字列のループ部は、文字列を回文必要があります(これを見ることができます理解していない:ABCABCABC)
lenが偶数であるためので、サイクルは、例えば、2112,1221、結果として展開され、セクションの後スワップ部前後で同じサイクルを引き起こす中間部分から取り外すことができるので、この時間の寄与は2で除算され。
長さが奇数のための中間体である場合には、長手方向延長部は、依然として異なる結果が、それは2で除算されていない後段をスワップアウト。
そのため同じ答えに同じ回文文字列をLEN寄与は、各番号の回文文字列LENのためので、統計を表現することができます。
そしてためlenがNの因数でなければならない(ループに他)、直接ルート因子ようにN N前処理します。
コード
#include <アルゴリズム> の#include <iostreamの> する#include <ベクトル> の#include <cmath> 使用して名前空間std。 #defineが長いlong int型 の#define MOD(int)を十億七 の#define N 64000 ベクトル<整数> VEC。 INT TOT [N]。 INTのPOW(INTベース、アップINT) { int型ANS = 1。 (アップ)、一方 、{ (アップ&1)ANS * =ベース、もしANS%= MOD。 ベース* =ベース。 基地%= MOD。 アップ>> = 1; } 戻りANS。 } )(主符号付き { lenを、INT N、K。 CIN >> N >> K。 LEN = SQRT(N)。 IF(N%I == 0)//获取所有可能的循环节长度ため(iは++; iは= LEN <I = 1 INT) { vec.push_back(I)。 IF(!= N-I / I)vec.push_back(N / I); } ソート(vec.begin()、vec.end()); INT ANS = 0; のための(I = 0 intです。私はVECを<サイズ();私は++) { TOT [I] = POW(K、(VEC [i]が+ +1)/ 2); //サイクル長部VEC [i]はループ部の数。パリンドローム配列ので、それはパリンドローム配列の全体の前半を決定することができる知っていることだけが必要であり、以下は同じ理由である ため(INT J = 0; J <I、J ++)(VEC [i]は%VEC [J]場合= 0 =) TOT [I] - TOT = [J]、TOT [I] =(TOT [I] + MOD)MOD%; // [削除長VEC [I]セクション場所を含む内部循環ループのセクション IF(VEC [I]&1)ANS + = [I] * VEC [I] TOT、ANS%= MOD; 他ANS + = TOT [I] *(VEC [I] / 2)、ANS%= MOD; } COUT < <ANS; }