結果
| 問題 | No.1269 I hate Fibonacci Number |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2021-06-14 00:17:30 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 118 ms / 3,000 ms |
| コード長 | 5,278 bytes |
| コンパイル時間 | 2,268 ms |
| コンパイル使用メモリ | 208,748 KB |
| 最終ジャッジ日時 | 2025-01-22 08:04:15 |
|
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 36 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
template <char MIN_CHAR = 'a', int ALPHABET = 26>
struct AhoCorasick
{
struct node
{
// suff : 先頭の文字を最小限消してグラフに存在する頂点にするときの行先の頂点
// dict : 先頭の文字を最小限消して辞書に存在する単語にするときの行先の頂点
// depth : Trie木における深さ(省略可能)
// word_index : このノードで終わる単語のindex(祖先は含まない。なければ-1)(複数ある場合は最小のもの)
// word_count : このノードで終わる単語の総数
// link : Trie及びsuffixの辺の接続先頂点(なければ-1)
int suff = -1, dict = -1, depth = 0;
int word_index = -1, word_count = 0;
int link[ALPHABET];
node() { fill(link, link + ALPHABET, -1); }
int& operator[](char c) { return link[c - MIN_CHAR]; }
};
// nodes : 頂点集合
// W : 現在の単語数
// word_location : 各単語のTrie木の最後の頂点のindex
// defer : 同じ単語が辞書内に存在する場合、最初の単語のindexを記録
vector<node> nodes;
int W;
vector<int> word_location;
vector<int> word_indices_by_depth;
vector<int> defer;
AhoCorasick() {};
AhoCorasick(const vector<string>& words = {})
{
build(words);
}
int get_or_add_child(int current, char c)
{
if (nodes[current][c] >= 0)
return nodes[current][c];
int index = int(nodes.size());
nodes[current][c] = index;
nodes.emplace_back();
nodes.back().depth = nodes[current].depth + 1;
return index;
}
int add_word(const string& word, int word_index)
{
assert(!nodes.empty());
int current = 0;
for (char c : word)
current = get_or_add_child(current, c);
if (nodes[current].word_index < 0)
nodes[current].word_index = word_index;
nodes[current].word_count++;
return current;
}
// locationからcを追加したときの行き先 O(1)
int get_suffix_link(int location, char c) const
{
if (location >= 0)
location = nodes[location].link[c - MIN_CHAR];
return max(location, 0);
}
void build(const vector<string>& words)
{
nodes = { node() };
W = int(words.size());
word_location.resize(W);
defer.resize(W);
int max_depth = 0;
for (int i = 0; i < W; i++)
{
word_location[i] = add_word(words[i], i);
max_depth = max(max_depth, int(words[i].size()));
defer[i] = nodes[word_location[i]].word_index;
}
word_indices_by_depth.resize(W);
vector<int> depth_freq(max_depth + 1, 0);
for (int i = 0; i < W; i++)
depth_freq[words[i].size()]++;
for (int i = max_depth - 1; i >= 0; i--)
depth_freq[i] += depth_freq[i + 1];
for (int i = 0; i < W; i++)
word_indices_by_depth[--depth_freq[words[i].size()]] = i;
vector<int> q = { 0 };
for (int i = 0; i < int(q.size()); i++)
{
int current = q[i];
for (char c = MIN_CHAR; c < MIN_CHAR + ALPHABET; c++)
{
int& index = nodes[current][c];
if (index >= 0)
{
int suffix_parent = get_suffix_link(nodes[current].suff, c);
nodes[index].suff = suffix_parent;
nodes[index].word_count += nodes[suffix_parent].word_count;
nodes[index].dict = nodes[suffix_parent].word_index < 0 ? nodes[suffix_parent].dict : suffix_parent;
q.push_back(index);
}
else
{
index = get_suffix_link(nodes[current].suff, c);
}
}
}
}
};
const long long int MOD = 1e9 + 7;
long long int dp[5005][1005];
int main(void)
{
cin.tie(0);
ios::sync_with_stdio(false);
long long int n, L, R;
vector <string> v;
cin >> n >> L >> R;
long long int f0 = 1;
long long int f1 = 1;
while (f0 <= R)
{
if (f0 >= L)
{
stringstream ss;
ss << f0;
v.push_back(ss.str());
}
long long int temp = f0 + f1;
f1 = f0;
f0 = temp;
}
AhoCorasick<'0', 10> aho(v);
dp[0][0] = 1;
for (int i = 0; i < n; i++)
{
for (int state = 0; state < aho.nodes.size(); state++)
{
for (int j = 0; j < 10; j++)
{
int nextstate = aho.get_suffix_link(state, '0' + j);
if (aho.nodes[nextstate].word_count == 0)
{
dp[i + 1][nextstate] += dp[i][state];
dp[i + 1][nextstate] %= MOD;
}
}
}
}
long long int res = 0;
for (int state = 0; state < aho.nodes.size(); state++)
{
res += dp[n][state];
res %= MOD;
}
res -= 1;
if (res < 0)
{
res += MOD;
}
cout << res << '\n';
return 0;
}