2019牛客暑期多校训练营(第三场)

目录

    • D Big Integer

D Big Integer

题意
求有多少对的 i i i j j j使得 A [ i j ] ≡ 0 A[i^j]\equiv 0 A[ij]0(mod p) 1 ⩽ i ⩽ n 1\leqslant i\leqslant n 1in 1 ⩽ j ⩽ m 1\leqslant j\leqslant m 1jm
其中A[n]表示有n位全1的十进制数,如 A [ 5 ] = 11111 A[5]=11111 A[5]=11111
思路
这题相当复杂啊,首先 111 … … 11 = 1 0 n − 1 9 111……11=\frac {10^n-1}{9} 11111=910n1,原式可化为 1 0 n ≡ 1 10^n\equiv1 10n1(mod 9p),
当p!=2或5时 g c d ( 10 , 9 p ) = 1 gcd(10,9p)=1 gcd(10,9p)=1,再根据欧拉定理可得 1 0 φ ( 9 p ) ≡ 1 10^{φ(9p)}\equiv 1 10φ(9p)1(mod 9p)本来化到这里其实就可以继续下一步了,但是因为在后面的计算中用9p会爆longlong,因此还需要继续化简,由于欧拉函数是积性函数, φ ( 9 p ) = φ ( 9 ) ∗ φ ( p ) = 6 ∗ ( p − 1 ) φ(9p)=φ(9)*φ(p)=6*(p-1) φ(9p)=φ(9)φ(p)=6(p1),由于最小循环节一定在 φ ( 9 p ) φ(9p) φ(9p)的因子中取,所以特判一下p=3的情况,然后只需要枚举 φ ( p ) φ(p) φ(p)的因子就好了。

网上搜的题解说 若有 n 对 1 0 n ≡ 1 ( m o d 9 p ) 10 n ≡ 1 ( m o d 9 p ) 10^n \equiv 1\pmod {9p}10 n≡1(mod9p) 10n1(mod9p)10n1(mod9p)成立, 那么一定有 1 0 n ≡ 1 ( m o d p ) 10 n ≡ 1 ( m o d p ) 10^n\equiv 1\pmod {p}10 n ≡1(modp) 10n1(modp)10n1(modp)成立,不是很懂这是什么定理

这样求得了最小循环节d,原题就转化为:有多少对的i,j使得 i j ≡ 0 i^j\equiv 0 ij0(mod d)

把 d 质因数分解: d = p 1 k 1 p 2 k 2 ⋯ p l k l d=p_1^{k_1}p_2^{k_2}\cdots p_l^{k_l} d=p1k1p2k2plkl, 要使得 i j i^j ij d d d 的倍数,那么在 i j i^j ij 的质因数分解中 p 1 , p 2 ⋯ p l p_1,p_2\cdots p_l p1,p2pl 的指数中都要比 d d d 中的大,所以我们考虑 j 固定的时候,有多少个 i 可以满足条件。
i i i 必须是 g = p 1 ⌈ k 1 j ⌉ p 2 ⌈ k 2 j ⌉ ⋯ p l ⌈ k l j ⌉ g = p_1^{\lceil {k_1\over j} \rceil} p_2^{\lceil {k_2\over j} \rceil}\cdots p_l^{\lceil {k_l\over j} \rceil} g=p1jk1p2jk2pljkl 的倍数,(至于为什么上取整,可以想一想,因为要求最小的 x x x, 有 x ∗ j > = k 1 & & x ∗ ( j − 1 ) < k 1 x*j >= k_1 \&\& x*(j-1) < k_1 xj>=k1&&x(j1)<k1 。因此一共有 n g n\over g gn个合法的 i i i
由于k最大不超过30,枚举j时只要枚举到30,大于30的解跟30的情况是一样的

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
//const int mod = 998244353;
const int maxn = 1e5+20;
ll p;
int n,m;
ll fac[maxn],num[maxn];
int cnt;
ll qmod(ll a,ll b,ll mod)
{
    ll c=1;
    while(b)
    {
        if(b&1)
        {
            c=c*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return c;
}

ll getfac(ll x)                     //质因子分解
{
    cnt=0;
    memset(fac,0,sizeof(fac));
    memset(num,0,sizeof(num));
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            fac[++cnt]=i;
            while(x%i==0)
            {    ll p,n,m;
                num[cnt]++;
                x/=i;
            }
        }
    }
    if(x>1)
    {
        fac[++cnt]=x;
        num[cnt]++;
    }
}

int main(){
    int t;
    cin>>t;

    while(t--)
    {
        ll d;
        cin>>p>>n>>m;
        if(p==2||p==5)
        {
            printf("0\n");
            continue;
        }
        else if(p==3)
        {
            d=3;
        }
        else{
            d=p-1;
            getfac(d);
            for(int i=1;i<=cnt;i++)
            {
                for(int j=0;j<num[i];j++)
                {
                    if(qmod(10,d/fac[i],p)==1)
                        d/=fac[i];
                }
            }
        }
        getfac(d);              //分解d
        ll g;
        ll ans=0;
        for(int i=1;i<=min(30,m);i++)
        {
            g=1;
            for(int j=1;j<=cnt;j++)
            {
                int ma=(num[j]%i==0?num[j]/i:num[j]/i+1);
                for(int k=1;k<=ma;k++)
                {
                    g*=fac[j];
                }
            }
            ans+=n/g;
        }
        if(m>30)
            ans+=n/g*(m-30);
        printf("%lld\n",ans);

    }
}

你可能感兴趣的:(多校)