D 签到

题意

给你一个长度为 $n$ 的序列,你可以任意将相邻的两个元素合并为一个元素,该两个元素的权值将会相加。你可以进行无限多次操作,问多次操作后,序列中最多有多少个 $p$ 的倍数。

思路

因为是连续合并两个元素,那么多次相邻合并可以看成合并一个区间。那么相当于问你,有多少个不相交的区间,它的和是 $p$ 的倍数。

显然,若区间 $[l, r]$ 的和为 $p$ 的倍数,那么 sum[r] % p - sum[l - 1] % p = 0

那么我们只需贪心统计有多少个 sum[r] % p = sum[l - 1] % p 的不相交区间即可,也就是先选满足要求的区间,时间复杂度 $O(n)$

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int sum[N], que[N];
bool vis[N];

int main() {
    int t, n, p;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &p);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &sum[i]);
            sum[i] = (sum[i - 1] + sum[i]) % p;
        }

        int ans = 0, tot = 0;
        for (int i = 0; i <= n; ++i) {
            if (vis[sum[i]]) {
                while (tot) vis[que[--tot]] = false;
                ans++;
            }
            vis[sum[i]] = true;
            que[tot++] = sum[i];
        }
        while (tot) vis[que[--tot]] = false;
        printf("%d\n", ans);
    }
    return 0;
}