abc158
题解翻译器 2022-5-5
E题
这个题还是有点意思的。
我们定义 f i f_i fi 为从 i i i 位置开始的后缀字串形成的值。
对于一个子串
[
l
,
r
]
[l,r]
[l,r] ,他的值为 :
f
l
−
f
r
+
1
1
0
n
−
r
−
1
\frac{f_l - f_{r+1}}{10^{n-r-1}}
10n−r−1fl−fr+1
我们要求的是 :
f
l
−
f
r
+
1
1
0
n
−
r
−
1
=
0
m
o
d
p
\frac{f_l - f_{r+1}}{10^{n-r-1}} = 0 \mod p
10n−r−1fl−fr+1=0modp
对于
p
=
2
p = 2
p=2 或者
p
=
5
p=5
p=5:
能否被整除,只与最后一位有关,所以,我们可以 O ( n ) O(n) O(n) 处理出来这两种情况。
对于 p > 5 p > 5 p>5
显然 1 0 − k ≠ 0 m o d p 10 ^{-k} \neq 0 \mod p 10−k=0modp,注意这个 1 0 − k 10^{-k} 10−k 是指逆元。那么只要 f l − f r + 1 = 0 m o d p f_l - f_{r+1} = 0 \mod p fl−fr+1=0modp 即可。记录后缀同余值即可。
满足 f l = f r + 1 m o d p f_l = f_{r+1} \mod p fl=fr+1modp
F题
是道 d p dp dp 题,开始没想到。。。
很显然要先通过位置先排序。分析可以发现,每个机器人只有激活或不激活两种状态,并且只会影响到后面的机器人。
我们定义一个值 R i R_i Ri 为当前机器人会影响的最靠右的机器人的编号。显然这个 R i R_i Ri 具有迭代性(因为机器人激活的机器人也能激活后面的机器人/套娃)。
倒着 d p dp dp
每个机器人有激活或者不激活两种状态。
-
考虑不激活当前机器人,得到的贡献是
dp[i + 1]
-
考虑激活当前机器人,得到的贡献是
dp[R[i] + 1]
R[i]
怎么得到呢,显然是
R
[
i
]
=
m
a
x
(
R
[
j
]
x
j
<
x
i
+
d
i
)
R[i] = max(R[j]_{x_j<x_i+d_i})
R[i]=max(R[j]xj<xi+di)
二分即可。
当然我们发现有个性质,R[i]
有单调性和覆盖性。可以用一个栈(或者队列)来维护。具体看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
void sol()
{
int N;
cin >> N;
vector<int> dp(N + 3);
vector<pair<int,int> > s(N + 1);
for (int i = 0; i < N; ++i)
cin >> s[i].first >> s[i].second;
s[N].first = 2e9;
sort(s.begin(), s.end());
dp[N] = 1;
stack<pair<int,int> > stk;
for (int i = N - 1; i >= 0; --i)
{
dp[i] = dp[i + 1];
int x = s[i].first + s[i].second, next = i + 1;
while (!stk.empty() && x > s[stk.top().first].first)
{
next = stk.top().second;
stk.pop();
}
stk.push({i,next});
dp[i] = (dp[i] + dp[next]) % MOD;
}
cout << dp[0] << endl;
}
int main()
{
int T = 1;
// cin >> T;
while (T--) sol();
return 0;
}