2019夏牛客多校第三场D Big Integer

赛中花了四小时搞这题没搞出来,结果赛后发现\(p=3\)的特判写错了,哭哭

\(A(i^j)=\sum_{k=0}^{i^j-1}10^k=\frac{10^{i^j}-1}{9}\equiv0(mod\ p)\)

\(p \neq3\)时(划重点①!!!),有\(10^{i^j}\equiv1(mod\ p)\)

考虑到费马小定理,当\(gcd(10, p)=1\)时,即\(p \neq 2\)\(p\neq5\)时(划重点②!!!),有\(10^{i^j-(p-1)}\equiv10^{i^j-k(p-1)}\equiv...\equiv10^{i^j\%(p-1)}\equiv1\equiv10^0(mod\ p)\)

所以\(p-1\ | \ i^j\).

但是\(p-1\)不一定是使\(10^x\equiv1(mod\ p)\)的最小正整数\(x\),所以我们设\(q\)是这个最小的\(x\),使\(10^q\equiv1(mod\ p)\)

显然我们有\(q\ |\ p-1\),所以有\(q\ |\ i^j\).

这个\(q\)可以\(O(\sqrt{p}log_2p)\)的时间复杂度暴力求出。

接下来的问题就转化为了有多少对\(1 \leq i \leq n, 1\leq j\leq m\)使得\(q\ |\ i^j\).

考虑\(q\)的质因数分解式\(q=p_1^{e_1}p_2^{e_2}...p_x^{e_x}\),我们设集合\(P_q=\{p_1,p_2,...,p_x\}\)

再考虑\(i\)的质因数分解式\(i=r_1^{d_1}r_2^{d_2}...r_y^{d_y}\),集合\(P_i=\{r_1,r_2,...,r_y\}\),显然只有当\(P_i \supset P_q\)时,才有可能有\(q\ |\ i^j\).

方便起见,改写\(i\)的分解式\(i=p_1^{d_1}p_2^{d_2}...p_x^{d_x}p_{x+1}^{d_{x+1}}...p_y^{d_y}\).

现在考虑这样一个问题:我们固定\(i\),有多少个\(j\)满足条件?

显然,\(\forall k \leq x,\)\(jd_k\geq e_k\),所以\(j\geq \lceil\frac{e_k}{d_k}\rceil\),所以满足条件的\(j\)\(m-{max}_{k=1}^x\lceil\frac{e_k}{d_k}\rceil+1\)个。

因此枚举\(i\)去算\(j\)的总最坏复杂度降到了\(O(nlogn)\)(?)

接下来我们枚举\(p_1,p_2,...,p_x\)的指数\(d_1,d_2,...,d_x\),考虑有多少个\(1\leq i \leq n\)使得它的质因数分解式\(i=p_1^{f_1}p_2^{f_2}...p_x^{f_x}p_{x+1}^{f_{x+1}}...p_y^{f_y}\)\(d_1=f_1,d_2=f_2,...,d_x=f_x\).

这个可以容斥来做,容易求出\(f_1\geq d_1,f_2\geq d_2,...,f_x\geq d_x\)\(i\)的个数为\(\lfloor\frac{n}{p_1^{d_1}p_2^{d_2}...p_x^{d_x}}\rfloor\)

容斥地加加减减\(f_k\geq d_k+1\)\(i\)的个数,就能算出最后结果。

复杂度?我不会算,但是因为\(p\)不会超过8个,所以目测\(O(\)能过\()\)......我只跑了12ms......

总复杂度\(O(\sqrt plog_2p+\)能过\()\).(???)

#include <bits/stdc++.h>
#define LL long long
#define MAXN 100008
using namespace std;

LL p, n, m;
LL q;
LL qp(LL a, LL b, LL mod)
{
    LL ret = 1;
    while (b)
    {
        if (b & 1)
            ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}

LL prime[18], ans;
int e[18];
int primelen = 0;
int d[18];

LL getval(LL msk, LL prod)
{
    int cnt1 = 0;
    for (int i = 0; i < primelen; ++i)
    {
        if (msk & (1 << i))
        {
            cnt1++;
            prod *= prime[i + 1];
            if (prod > n)
                return 0;
        }
    }
    if (cnt1 % 2)
        return - (n / prod);
    else
        return n / prod;
}
void dfs(int d[], int i, LL prod)
{
    if (prod > n)
        return;
    if (i > primelen)
    {
        LL ret = 0;
        for (int msk = 0; msk < (1 << primelen); ++msk)
        {
            ret += getval(msk, prod);
        }
        //cout << "ret = " << ret << endl;
        int mx = -1;
        for (int j = 1; j <= primelen; ++j)
        {
            mx = max(mx, (int)ceil(e[j] * 1.0 / d[j]));
        }
        //cout << "mx = " << mx << endl;
        ans += max(0LL, m - mx + 1) * ret;
        return;
    }
    LL cprod = prod;
    for (d[i] = 1; cprod * prime[i] <= n; ++d[i])
    {
        cprod *= prime[i];
        dfs(d, i + 1, cprod);
    }
    return;
}


int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        ans = 0;
        memset(prime, 0, sizeof(prime));
        memset(d, 0, sizeof(d));
        memset(e, 0, sizeof(e));
        primelen = 0;
        q = 0x3f3f3f3f;
        scanf("%lld %lld %lld", &p, &n, &m);
        for (LL i = 1; i * i <= p - 1; ++i)
        {
            if ((p - 1) % i)
                continue;
            if (qp(10, i, p) == 1)
                q = min(q, i);
            if (qp(10, (p - 1) / i, p) == 1)
                q = min(q, (p - 1) / i);
        }
        //cout << "q = " << q << endl;
        LL temp = q;
        for (int i = 2; i * i <= temp; ++i)
        {
            if (temp % i == 0)
            {
                prime[++primelen] = i;
                while (temp % i == 0)
                {
                    temp /= i;
                    e[primelen]++;
                }
            }
        }
        if (temp > 1)
        {
            prime[++primelen] = temp;
            temp = 1;
            e[primelen] = 1;
        }
        dfs(d + 1, 1, 1);
        if (p == 2 || p == 5 || q >= 0x3f3f3f3f)
            ans = 0;
        else if (p == 3)
            ans = (n / 3) * m;
        printf("%lld\n", ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/zhugezy/p/11247545.html