P4720
后缀自动机SAM
建 SAM
,对于每个节点维护一个区间 \([l,r]\) 表示这个节点即其儿子能到的最大和最小的原串上的位置
对于每个点,答案为 \(min(r-l+1,len)\) ,因为要保证不能重复
// Author: xiaruize
#ifndef ONLINE_JUDGE
bool start_of_memory_use;
#endif
#include <bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
clock_t start_clock = clock();
#endif
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
int min(int a, int b)
{
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 2e5 + 10;
int n, a, b, c, d;
bool s[N];
struct SAM
{
struct node
{
int len, lnk, nxt[2];
int mi, mx;
} s[N];
int cnt = 1, la = 1;
void ins(int x, int id)
{
int cur = ++cnt, p = la;
s[cur].len = s[la].len + 1;
while (p && !s[p].nxt[x])
{
s[p].nxt[x] = cur;
p = s[p].lnk;
}
int q = s[p].nxt[x];
if (!p)
s[cur].lnk = 1;
else if (s[p].len + 1 == s[q].len)
s[cur].lnk = q;
else
{
int r = ++cnt;
s[r] = s[q];
s[r].len = s[p].len + 1;
s[r].mx = 0;
s[r].mi = n;
while (p && s[p].nxt[x] == q)
{
s[p].nxt[x] = r;
p = s[p].lnk;
}
s[cur].lnk = s[q].lnk = r;
}
s[cur].mi = s[cur].mx = id;
la = cur;
}
} sam;
vector<int> g[N];
void dfs(int x)
{
for (auto v : g[x])
{
dfs(v);
sam.s[x].mi = min(sam.s[x].mi, sam.s[v].mi);
sam.s[x].mx = max(sam.s[x].mx, sam.s[v].mx);
}
}
void solve()
{
cin >> a >> b >> c >> d >> n;
for (int i = 0; i < a; ++i)
{
b = (b * c + d) % n;
s[b + 1] = true;
}
rep(i, 1, n) sam.ins(s[i], i);
rep(i, 2, sam.cnt) g[sam.s[i].lnk].push_back(i);
dfs(1);
int res = 0;
rep(i, 2, sam.cnt) res += max(min(sam.s[i].mx - sam.s[i].mi, sam.s[i].len) - sam.s[sam.s[i].lnk].len, 0ll);
cout << res << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}