zoukankan      html  css  js  c++  java
  • 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);
        }
    }
    
  • 相关阅读:
    SQL Convert的用法[转]
    C#里巧用DateTime预设一些可选的日期范围(如本年度、本季度、本月等)
    JS 操作IE游览器常用函数:window.external,history,document.execCommand
    sqoop基本应用
    SQLSever图形化界面基本使用
    hadoop 无法退出安全模式 内存够用
    Class<?> b=Class.forName(cName);
    每日学习20210925
    每日学习20210924
    hive 报错:Map local work exhausted memory
  • 原文地址:https://www.cnblogs.com/zhugezy/p/11247545.html
Copyright © 2011-2022 走看看