题目链接:点我啊╭(╯^╰)╮
题目大意:
给定一个长度为
n
n
n 的字符串
S
S
S,字符串满足
“
01234567890123
…
”
“01234567890123…”
“01234567890123…”
给出数列
p
p
p 和
d
d
d,
p
p
p 是一个排列
n
n
n 次操作,每次将
S
S
S 串的
p
[
i
]
p[i]
p[i] 位置的数字替换成
d
[
i
]
d[i]
d[i] ,得到
S
i
S_i
Si
求对这
n
n
n 个
S
0
~
S
n
S_0~S_n
S0~Sn 按字典序排序后的顺序是多少
解题思路:
若第
i
i
i 次操作是将
S
[
p
i
]
S[p_i]
S[pi] 替换为
d
i
d_i
di,且
d
i
<
S
[
p
i
]
d_i < S[p_i]
di<S[pi]
则替换之后字典序会变小,也就是
[
i
,
n
]
[i,n]
[i,n] 的字符串的顺序要小于
[
0
,
i
−
1
]
[0,i-1]
[0,i−1]
而且
p
i
p_i
pi 越小,要越先考虑,因此可以分治解决
若当前处理到
[
l
,
r
]
[l,r]
[l,r],
p
p
p 的最小值的位置在
i
i
i,且
d
i
<
S
[
p
i
]
d_i < S[p_i]
di<S[pi]
因此按照顺序从小到大处理,先处理
[
i
+
1
,
r
]
[i+1,r]
[i+1,r],然后处理
[
l
,
i
]
[l,i]
[l,i]
表示
[
i
+
1
,
r
]
[i+1,r]
[i+1,r] 排序后的顺序要在
[
l
,
i
]
[l,i]
[l,i] 之前,
d
i
>
S
[
p
i
]
d_i > S[p_i]
di>S[pi] 的情况反过来处理即可
关键是
d
i
=
S
[
p
i
]
d_i = S[p_i]
di=S[pi] 的情况,等同于第
i
i
i 次操作后,字典序没有任何变化
而在这次操作之前以及之后,字典序发生变化都能影响答案
因此,直接将
p
i
p_i
pi 赋值为无穷大,因此在找最小
p
p
p 的时候,跳过了这次操作
然后需要解决区间最小值的问题,这道题只能满足
O
(
n
)
O(n)
O(n) 的做法
考虑到
p
p
p 是一个排列,因此分治的过程可以直接在笛卡尔树上
d
f
s
dfs
dfs
时间复杂度:
O
(
n
)
O(n)
O(n)
也可以直接单调栈 + 差分来做,好像更简单
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 2e6 + 5;
const ll mod = 1e9 + 7;
int T, n, cnt, p[maxn], d[maxn];
int q[maxn], ans[maxn];
int st[maxn], fa[maxn];
int ls[maxn], rs[maxn];
void build() {
int tail = 0;
for(int i=0; i<n; i++) {
int t = tail;
while(t && p[st[t]] > p[i]) t--;
if(t < tail) ls[i] = st[t+1], fa[ls[i]] = i;
if(t) rs[st[t]] = i, fa[i] = st[t];
st[++t] = i; tail = t;
}
}
void dfs(int l, int r, int pos) {
if(l > r) return;
if(l == r) { ans[l] = cnt++; return; }
if(p[pos] == 2e9) {
for(int i=l; i<=r; i++) ans[i] = cnt++;
return;
}
if(d[pos] < p[pos] % 10) dfs(pos+1, r, rs[pos]), dfs(l, pos, ls[pos]);
else dfs(l, pos, ls[pos]), dfs(pos+1, r, rs[pos]);
}
signed main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
int pseed, pa, pb, pmod;
scanf("%d%d%d%d", &pseed, &pa, &pb, &pmod);
for(int i=0; i<n; i++) p[i] = i;
for(int i=1; i<n; i++) {
swap(p[pseed%(i+1)], p[i]);
pseed = (1ll * pseed * pa % pmod + pb) % pmod;
}
int dseed, da, db, dmod;
scanf("%d%d%d%d", &dseed, &da, &db, &dmod);
for(int i=0; i<n; i++) {
d[i] = dseed % 10;
dseed = (1ll * dseed * da % dmod + db) % dmod;
}
for(int i=0; i<n; i++)
if(d[i] == p[i] % 10) p[i] = 2e9;
build(); cnt = 0;
dfs(0, n, st[1]);
ll ret = 0, tmp = 1;
for(int i=0; i<=n; i++) {
ret = (ret + 1ll * ans[i] * tmp % mod) % mod;
tmp = tmp * 10000019 % mod;
}
printf("%lld\n", ret);
}
}