/* O(n^2 log n) dp + NTT */ #include #include #include #include #include #include #include #include #include using namespace std; void timer(){ static chrono::steady_clock::time_point start = chrono::steady_clock::now(); auto now = chrono::steady_clock::now(); cerr << "elapsed time : " << chrono::duration_cast(now-start).count() << "[ms]" << endl; } const long long mod = 1000000007; long long ans[10001]; long long fact[10001]; long long fact_inv[10001]; long long mod_pow(long long x, long long y, long long mod){ //(x^y) % mod if(x==0 && y!=0) return 0; long long ret=1LL; while(y>0LL){ if(y&1LL) ret = (ret * x) % mod; x = (x*x) % mod; y >>= 1LL; } return ret; } long long extgcd(long long a, long long b, long long &x, long long &y){ long long d=a; if(b!=0){ d = extgcd(b, a%b, y, x); y -= (a/b) * x; }else{ x = 1; y = 0; } return d; } long long mod_inverse(long long a, long long m){ long long x,y; extgcd(a,m,x,y); return (m+x%m)%m; } template class Number_Theoretic_Transform { // return the vector of F[t] or f[x] where // F[t] = sum of { f[x] * exp(-j * theta * t * x) } in x = 0 .. N-1 (FFT) // f(x) = 1/N * sum of { F[t] * exp(j * theta * t * x) } in t = 0 .. N-1 (inverse FFT) // where theta = 2*PI / N // N == 2^k // use the rotater as (primitive-root of mod) ^ t in NTT, which is used as exp(j*theta)^t in FFT //事前に計算した 単位回転子 rotater (MOD mod 上での位数が2^kとなる数) を 引数に与える。 //逆変換のときには rotater^-1 (MOD mod) を rotaterに与える vector< T > do_NTT(vector< T > A, bool inverse){ int N = A.size(); //bit reverse for(int bit=0; bit>= 1){ rbit |= tmp_bit & 1; } rbit >>= 1; if(bit < rbit){ swap(A[bit], A[rbit]); } } int dist = 1; vector& theta = (inverse?inv_theta_v:theta_v); T t = k-1; T half = theta[k-1]; //半回転 for(int level = 1; level= mod) tmp %= mod; A[y+dist] = A[y] + (tmp*half) % mod; if(A[y+dist] >= mod) A[y+dist] %= mod; A[y] = A[y] + tmp; if(A[y] >= mod) A[y] %= mod; } W = W*W_n; if(W>=mod) W%=mod; } dist <<= 1; t -= 1; } if(inverse){ for(int i=0; i= mod) A[i] %= mod; } } return A; } public: const T mod; const T rotater; const T inv_rotater; const T k; vector theta_v; vector inv_theta_v; const T z; Number_Theoretic_Transform(T mod_, T rotater_, T k_) : mod(mod_), rotater(rotater_), k(k_), inv_rotater(mod_inverse(rotater_, mod)), z(mod_inverse(1<<(k-1), mod)) // 1/Nを掛けるところなので N^-1 MOD modを掛けたいところだけど何故か (N/2)^-1 で上手く行く…… { theta_v = vector(k+1,1); theta_v[0] = rotater; for(int i=1; i<=k; i++){ theta_v[i] = theta_v[i-1] * theta_v[i-1]; if(theta_v[i] >= mod) theta_v[i] %= mod; } inv_theta_v = vector(k+1,1); inv_theta_v[0] = inv_rotater; for(int i=1; i<=k; i++){ inv_theta_v[i] = inv_theta_v[i-1] * inv_theta_v[i-1]; if(inv_theta_v[i] >= mod) inv_theta_v[i] %= mod; } }; vector< T > NTT(vector< T > A){ return do_NTT(A, false); } vector< T > INTT(vector< T > A){ return do_NTT(A, true); } // vector C | C[i] = ΣA[i]B[size-1-j] vector convolution(vector &A, vector &B){ int n = A.size(); assert(A.size() == B.size()); assert( n == (1<= mod) A_NTT[i] %= mod; } return INTT(A_NTT); } }; long long gcd(long long a, long long b){ if(b==0) return a; return gcd(b, a%b); } long long lcm(long long a, long long b){ if(a x, vector y, long long MOD){ int N = x.size(); bool valid = true; //前処理 //gcd(Yi,Yj) == 1 (i!=j) でなくてはならないので、 //共通の因数 g = gcd(Yi,Yj) を見つけたら片側に寄せてしまう for(int i=0; i z(N); for(int i=0; i child; int count; }; vector trie; vector s[200001]; vector w[200001]; vector convolution(vector a, vector b){ int x = a.size(); int y = b.size(); if(x*y <= (x+y)*30 ){ vector res(x+y-1); for(int i=0; i>> param = { { }, { }, { {2, 17011, 4989209}, {2, 7027, 4937873}, {2, 12941, 4925573}, }, { {3, 13003, 4827737}, {3, 9521, 4813577}, {3, 10079, 4767457}, }, { {4, 15859, 4899329}, {4, 4679, 4895057}, {4, 15749, 4866209}, }, { {5, 15817, 4994401}, {5, 15227, 4988449}, {5, 14947, 4917217}, }, { {6, 8117, 4989121}, {6, 17123, 4974913}, {6, 761, 4952257}, }, { {7, 14551, 4928513}, {7, 9781, 4832257}, {7, 4663, 4797953}, }, { {8, 4973, 4933889}, {8, 10159, 4856321}, {8, 16229, 4817921}, }, { {9, 10567, 4996609}, {9, 12143, 4996097}, {9, 13249, 4984321}, }, { {10, 631, 4995073}, {10, 15727, 4979713}, {10, 14029, 4953089}, }, { {11, 3041, 4933633}, {11, 4201, 4909057}, {11, 569, 93493249}, }, { {12, 16633, 4902913}, {12, 5527, 4845569}, {12, 1009, 97497089}, }, { {13, 13687, 48701441}, {13, 709, 4866049}, {13, 163, 4816897}, }, { {14, 24763, 99500033}, {14, 26249, 99106817}, {14, 14867, 98992129}, }, { {15, 9859, 98861057}, {15, 6427, 97615873}, {15, 11393, 97320961}, }, }; vector P; vector R; vector> tmp(3); for(int i=0; i<3; i++){ R.push_back( param[k][i][1] ); P.push_back( param[k][i][2] ); assert( mod_pow(R[i], 1< NTT(P[i], R[i], k); tmp[i] = NTT.convolution(a,b); } vector res(x+y-1); for(int i=0; i w = {tmp[0][i], tmp[1][i], tmp[2][i]}; res[i] = Chinese_Remainder_Theorem_Garner(w,P, mod); } return res; } // dp[i][x] := i 頂点で合計長 x の組み合わせ void dfs(int pos, long long d){ if( trie[pos].count == 1 ){ w[pos].resize(2); s[pos].resize(2); w[pos][0] = w[pos][1] = 1; s[pos][0] = 0; s[pos][1] = 1; return; } if( trie[pos].child.size() == 1 ){ int nx = trie[pos].child.begin()->second; dfs(nx, d+1); swap( s[pos], s[nx] ); swap( w[pos], w[nx] ); return; } w[pos].resize(1); s[pos].resize(1); w[pos][0] = 1; s[pos][0] = 0; for(auto p : trie[pos].child){ if( p.first == '}' ) continue; int nx = p.second; dfs(nx, 1); for(int i=1; i s_(w_.size()); for(int i=0; i= w_.size()){ // w_.resize(i+j+1); // s_.resize(i+j+1); // } // (w_[i+j] += w[pos][i] * w[nx][j] % mod) %= mod; // (s_[i+j] += s[pos][i] * w[nx][j] % mod) %= mod; // (s_[i+j] += w[pos][i] * s[nx][j] % mod) %= mod; // } // } swap(w[pos], w_); swap(s[pos], s_); for(int i=1; i(i, trie[pos].count-1)%mod * w[pos][i]) %= mod; } } int main(){ timer(); fact[0] = fact_inv[0] = 1; for(int i=1; i<10001; i++){ fact[i] = fact[i-1] * i % mod; fact_inv[i] = mod_pow(fact[i], mod-2, mod); } int n; cin >> n; vector s_(n); for(int i=0; i> s_[i]; s_[i] += '{'; } s_.push_back("}"); trie.push_back( trie_node{{}, 0} ); for(int i=0; i