P5379

首先每个数取模显然没有影响。

反过来推,胜利状态显然是所有数全部为 $0$,$1$ 步胜利状态则是所有数全部相等($>0$),$2$ 步为整个数列差分后全等。

证明很简单,就是因为你对于任何一个 $x$,$A_i+B_{i+x}$ 都要等于 $A_{i+1}+B_{i+x+1}$。

得到结论:答案 $k$ 为一个最小的整数,使数列经过 $k-1$ 阶差分后全等。

考虑 $i$ 阶差分怎么求。$i$ 显然可以分解成一系列 $p^k$ 的和。

转化为求解 $p^k$ 阶差分。设 $k=p^k$。

发现高阶差分过程很像杨辉倒三角,每个数的贡献为 $C_k^i$。

二项式反演得到:$A_i = \displaystyle\sum_{j=0}^k(-1)^j\times A_{i+j}\times C_k^j$。

由于 $k$ 是质数,$C_k^j\bmod k=0$。

证明:首先 $k$ 不包含任何因数,于是在除 $i$ 的时候,$k$ 不会被波及。而已经乘了 $i$ 个连续的数,所以一定有一个数有因数 $i$。

于是 $j=[1,k-1]$ 的情况作废。

剩下两项贡献,$A_i$ 为 $(-1)^0=1$ 倍,$A_{i+k}$ 为 $(-1)^k=-1$ 倍(质数一定是奇数,$2$ 单独讨论)

得到结论:$k$ 阶差分相当于 $A_i \to A_i - A_{i+k}$。

现在 $check$ 函数和差分函数已经完成,只需要分解一下 $n$,然后对贡献求和就可以了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
int n, p, a[N];
inline bool check(int len)
{
    for (int i = len + 1; i <= n; i++)
        if (a[i] != a[(i - 1) % len + 1])
            return false;
    return true;
}
inline void avicii(int len)
{
    static int tmp[N];
    for (int i = 1; i <= n; i++)
        tmp[i] = (a[i] - a[(i + len - 1) % n + 1] + p) % p;
    memcpy(a, tmp, sizeof(tmp));
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> p;
    for (int i = 1; i <= n; i++)
        cin >> a[i], a[i] %= p;
    int t = 1;
    while (!(n % (t * p)))
        t *= p;
    if (!check(t))
    {
        cout << -1;
        return 0;
    }
    int ans = 0;
    n = t;
    while (n > 1)
    {
        t = n / p;
        while (!check(t))
            avicii(t), ans += t;
        n /= p;
    }
    cout << ans + (a[1] > 0);
    return 0;
}

 

posted @ 2023-05-11 20:09  creation_hy  阅读(24)  评论(0编辑  收藏  举报