Luogu P10066 Solution

闲话

时隔许久,我终于又独立做对了一道蓝题,所以写一篇题解。

(但这道题真的是蓝题吗)

题解

首先对题目性质进行一个简单的分析。

设原数组为 \(a\),SMS 数组为 \(b\),下标从 \(0\) 开始,可以列出以下的算式:

\[b_x=\sum_{i=x}^{x+k-1} a_i \]

此时,我们将 \(0\)\(1\) 代入式子,发现它们的大小关系只会被 \(a_0\)\(a_k\) 的大小关系影响。为什么?因为,它们的求和范围的区别有且仅有这两个元素。

于是,我们可以发现一个重要的性质:

在给定数组 \(b\) 且合法的情况下,确定数组 \(a\) 的前 \(k\) 个元素等同于确定整个数组 \(a\)

那么,怎么利用这个性质呢?

首先,注意到一个事实:由于根据 \(b\) 数组决定的 \(a\) 下标同余元素的大小关系有等于、小于、大于三种,并且保证 \(b\) 至少对应一个合法的 \(a\),且 \(a\) 仅包含 \(0\)\(1\),所以对于 \(0\)\((k-1)\) 中任意一个对 \(k\) 取模的结果,只要有其中一个确定了非等于的关系,那么所有同余下标的元素实际上都被锁死了。

于是,在对整个 \(b\) 数组做完上述的判断后,我们会发现此时 \(a\) 的前 \(k\) 个元素有三种取值:\(0\)\(1\)\(0/1\)

此时,依据 \(b_0\) 的值,我们可以容易地使用组合数确定可选方案的个数。

时间复杂度 \(O(n)\)

代码

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e6 + 10, mod = 1e6 + 3;
int n, k, a[N], req[N], rn;
using ll = long long;
ll fac[N];
inline ll fsp(ll x, ll y)
{
    ll res = 1;
    while (y)
    {
        if (y & 1)
            res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res;
}
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i <= n - k; i++)
    {
        scanf("%d", a + i);
    }
    memset(req, -1, k << 2);
    for (int i = 0; i < n - k; i++)
    {
        if (a[i] != a[i + 1] and !~req[i % k])
        {
            req[i % k] = (a[i] > a[i + 1]);
        }
    }
    for (int i = 0; i < k; i++)
    {
        if (~req[i])
            a[0] -= req[i];
        else
            rn++;
    }
    fac[0] = 1;
    for (int i = 1; i <= rn; i++)
    {
        fac[i] = fac[i - 1] * i % mod;
    }
    printf("%lld\n", fac[rn] * fsp(fac[a[0]], mod - 2) % mod * fsp(fac[rn - a[0]], mod - 2) % mod);
}
posted @ 2024-10-04 07:06  丝羽绫华  阅读(2)  评论(0编辑  收藏  举报