轨道

题目大意

对于以下公式:

v=a1a2...ankv=\frac{a_1*a_2*...*a_n}{k}

已知 nnkk1in,1aim\forall 1 \leq i \leq n, 1 \leq a_i \leq m,问有多少个序列 aa 满足 vvkk 为互质正整数。

注:相同的元素,不同的排列,算不同的方案。

对于 100%100\% 的数据 1<=n<=3000,1<=m<=109,1<=k<=1071<=n<=3000,1<=m<=10^9,1<=k<=10^7

解题思路

一道好题。

20pts

暴力 dfsdfs,求出 vvgcd\gcd 判断 v,kv, k 是否为互质正整数即可。

时间复杂度为 O(mn)\mathcal{O}(m^n) ,这不用说了吧。。。

100pts

考虑 DP

dpi,jdp_{i, j}x=1iax=j\prod\limits_{x = 1}^i a_x = j 的方案数。

那么最终的答案即为 dpn,p\sum dp_{n, p},其中 pp 满足 pk\frac{p}{k} 与 k$ 为互质正整数。

但这样做显然空间又大时间又大,所以我们可以换个状态。

由于题意是让 i=1nai\prod\limits_{i = 1}^n a_i 可以整除 kk 且除以 kk 的商与 kk 为互质正整数,所以我们只需关心 \prod\limits_{i = 1}^n a_i k$ 的质因子的个数即可。

因此可以把上述状态优化成如下状态:

dpi,jdp_{i, j} 表示 k=1iak\prod\limits_{k = 1}^i a_kkk 的最大公因数为 kk 的第 jj 个因数的方案总数。

由定义知 k=1iak\prod\limits_{k = 1}^i a_k 除以该公因数的商与 kk 本身互质,否则该数肯定不是最大公因数。1

pip_ikk 的第 ii 个因数。

于是,最终的答案即为 dpn,lenpdp_{n, len_p}

再考虑转移方程,根据 dpi,jdp_{i, j} 的定义,我们需要用前 ii 个数凑出 pjp_j 的倍数,那么不妨用前 i1i - 1 个数凑出满足题目条件的 pxp_x 的倍数,再令第 ii 个数为满足题目条件的 pjpx\frac{p_j}{p_x} 的倍数,从而凑出 pjp_j 的倍数。

因为 pjp_jkk 的因数,pjpx\frac{p_j}{p_x} 又是 pjp_j 的因数,所以 pjpx\frac{p_j}{p_x} 也一定是 kk 的因数。

假设 pjpx\frac{p_j}{p_x}kk 的第 rr 个因数,pjmodpx=0,dpi,j=(dpi1,x×dp1,r)\forall p_j \operatorname{mod} p_x = 0, dp_{i, j} = \sum\limits (dp_{i - 1, x} \times dp_{1, r}),即用 i1i - 1 个数凑出符合要求的 pxp_x 的倍数的方案总数 * 符合要求的 pjpx\frac{p_j}{p_x} 的倍数的个数,再求和。

然后再考虑 DP 的边界条件,1il,dp1,i\forall 1 \leq i \leq l, dp_{1, i} 即为 [1,m][1, m] 中与 kk 的最大公因数为 pip_i 并且除以 pip_i 的商与 kk 互质的正整数个数。

假设 xx 是一个符合要求的整数,那么 gcd(x,k)=pi\gcd(x, k) = p_i

我们可以把这个式子稍微变形一下:dp1,idp_{1, i} 等于 1ympigcd(y,k)=1\forall 1 \leq y \leq \lfloor \frac{m}{p_i} \rfloor,gcd(y, k) = 1 的整数 yy 的个数。

如何维护上面的式子?令 qqkk质因数序列。

我们发现 [1,mpi][1, \lfloor \frac{m}{p_i} \rfloor] 中与 kk 互质的数个数似乎是 mpi\lfloor \frac{m}{p_i} \rfloor 减去取值范围内 q1,q2,...,qlenq_1, q_2, ..., q_{len} 倍数的个数。

但是这样会重复减去 qiqjq_i * q_j 倍数的个数,因此还需要把它们加回来。

显然这是一个 容斥原理

每次容斥的值可以简单地确定:显然我们需要减去所有 qiq_i 的倍数的个数,再加上 qiqjq_i * q_j 的倍数的个数,接着减去 qi×qj×qxq_i \times q_j \times q_x 的倍数的个数……

奇数个质因子之积的倍数个数系数应该为 1-1,反之为 11,这样我们就需要枚举每一种可能的质因数组合,时间复杂度在 22 的幂次方级别。

时间复杂度即为 O(2x×len+nlen2)\mathcal{O}(2^{x} \times len + nlen^2)

AC CODE

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

const int mod = 10007;

int n, m, k;

int sum, p;

int dp[3007][4007], tar[10000007];

int flen, fac[4007], plen, prime[4007], fact[4007][4007];

void dfs(int dep, int val, int g)
{
    if (dep > plen)
    {
        sum += (p / val * g);
        return;
    }
    dfs(dep + 1, val, g);
    dfs(dep + 1, val * prime[dep], -g);
}

signed main()
{
    scanf("%d%d%d", &n, &m, &k);

    for (int i = 1; i * i <= k; i++)
        if (k % i == 0)
        {
            fac[++flen] = i;
            if (k / i != i)
                fac[++flen] = k / i;
        }
    sort(fac + 1, fac + flen + 1);

    int val = k;
    for (int i = 2; i * i <= k; i++)
    {
        if (val % i == 0)
        {
            prime[++plen] = i;
            while (val % i == 0)
                val /= i;
        }
    }
    if (val != 1)
        prime[++plen] = val;
    sort(prime + 1, prime + plen + 1);

    for (int i = 1; i <= flen; i++)
    {
        tar[fac[i]] = i;
        sum = 0;
        p = m / fac[i];
        dfs(1, 1, 1);
        dp[1][i] = sum % mod;
    }

    for (int i = 1; i <= flen; i++)
        for (int j = 1; j <= i; j++)
            if (fac[i] % fac[j] == 0)
                fact[i][++fact[i][0]] = j;

    for (int i = 2; i <= n; i++)
        for (int j = 1; j <= flen; j++)
            for (int k = 1; k <= fact[j][0]; k++)
                dp[i][j] = (dp[i][j] + dp[i - 1][fact[j][k]] * dp[1][tar[fac[j] / fac[fact[j][k]]]]) % mod;

    printf("%d\n", dp[n][flen]);
    return 0;
}

Footnotes

  1. 简证:设该数,即 x=1iax\prod\limits_{x = 1}^i a_xkk 最大公因数为 WW,则 x=1iax=Wu1,k=Wu2\prod\limits_{x = 1}^i a_x=W*u_1,k=W*u_2gcd(u1,u2)=1\gcd(u_1,u_2)=1,由定义得,x=1iaxk\frac{\prod\limits_{x = 1}^i a_x}{k} 为正整数,即 u1u2\frac{u_1}{u_2} 为正整数,又因为 gcd(u1,u2)=1\gcd(u_1,u_2)=1,所以 u2u_2 只能为 11k=Wk=W。证毕。

posted @ 2021-09-20 14:30  蒟蒻orz  阅读(5)  评论(0编辑  收藏  举报  来源