4.2 校内模拟赛游记

其实正解都想得挺快的,但是 D 题细节有些恶心,最终调了很久,没空做最后一题了。

A

一个字符串,若干个操作,每次翻转或在开头/结尾插入,输出最后结果。

水题,deque 解决。

B

一个字符串,维护区间内不同的字符个数,支持单点修改。

线段树裸题。

C

水题,题目都不想打了。

D

随便来个样例,把所有的列出来。

3
35
354
3543
 5
 54 
 543
  43
   3

中间显然有很多重复。

若只维护第一组,那么每次每个要减去的数不一样,所以从后面开始。

   3
  43
 543
3543
  4
 54
354
 5
35
3

这样对于每一组,就是把第一个去掉,然后剩下的每一个减去最后一个位再除以十就可以了。

因为对于所有数的处理都一样,所以直接把取模完每一个答案有几个给记下来,然后维护一个 kk, 满足经过了哪些操作原来答案为 kk 的答案会变为 00, 然后加上这个就可以了。

具体地,比如有 55 个数,我现在要求倒数第二组的答案,则 kk 需要满足(invinv1010 的逆元)

((((((ks5)×inv)s4)×inv)s3)×inv0(modp)((((((k-s_5)\times inv) - s_4) \times inv) - s_3) \times inv \equiv 0 \pmod p

化简一下就是每次 kk 加上 si×10pows_i \times 10^{pow}

然后你就可以交了。

代码

#include <cstdio>
#define int long long
int n, m, p, ans, f[10005];
char s[200005];
signed main() {
    scanf("%lld%lld", &n, &p);
    scanf("%s", s + 1);
    for (int i = n, pow = 1, now = 0; i >= 1; i--, pow = pow * 10 % p) {
        now = (now + (s[i] - '0' + p) * pow % p) % p;
        f[now]++;
    }
    for (int i = n, pow = 1, now = 0; i >= 1; i--, pow = pow * 10 % p) {
        ans = ans + f[now];
        now = (now + (s[i] - '0') * pow % p) % p;
        f[now]--;
    }
    printf("%lld", ans);
}

交了以后会发现:WA 了

细细一想,发现若 pp1010 的约数时连个逆元都没有,你乘个锤子!

所以特判一下 pp2255 的情况。

    if (p == 2 || p == 5) {
        for (int i = 1; i <= n; i++)
            if ((s[i] - '0') % p == 0)
                ans += i;
        printf("%lld", ans);
        return 0;
    }

现在真的过了。这错误我调了 4040 分钟

E

原题是 ABC158F。

看了题解 觉得 dp 还是比较显然的,肯定得排一个序,然后倒着。因为我们能唯一能确定的状态就是 n+1n+1 这个编号,根本没有机器人,方案只有 11

fif_i 表示后 ii 个的方案数。显然可以 fi=fi+1+fnextf_i = f_{i+1} + f_{next}, 其中 nextnext 是后面不受影响的。

问题在于后面那个怎么求。 next 即后面第一个大于 x+d1x + d - 1 的,那不就是单调栈吗?

代码

#include <cstdio>
#include <stack>
#include <algorithm>
const int N = 200005, p = 998244353;
int n, f[N];
std::pair<int, int> a[N];
std::stack<std::pair<int, int> > st;
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d%d", &a[i].first, &a[i].second);
	std::sort(a+1, a+1+n);
	f[n+1] = 1;
	for(int i = n; i >= 1; i--) {
		int t = a[i].first + a[i].second, next = i+1;
		while(!st.empty() && t > a[st.top().first].first) {
			next = st.top().second;
			st.pop();
		}
		st.push({i, next});
		f[i] = (f[i+1] + f[next]) % p;
	}
	printf("%d", f[1]);
}