p4714 「数学」约数个数和

Posted creed-qwq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p4714 「数学」约数个数和相关的知识,希望对你有一定的参考价值。

题目求的东西可以转化为:

给你一个数,每次把它变成它的一个约数,重复k次,求方案数。(中间过程有一步不同则视为不同)

这个东西显然可以dp,但是n,k<=1e18。

考虑每个质因子分别算,就又转化为一个新的问题,给你一个数,每次可以把它变成一个<=它的数字,重复k次。求方案数。(中间过程有一步不同则视为不同)

这个可以直接插板法来算。设x=π pi^ti,则ans=πC(ti+1+k-1,ti)。

这里的组合数,虽然n是1e18级别的,但m的取值<=60,可以直接组合数横向递推来求。

然而我又自闭了,写了一个矩阵乘法优化dp来算qwq。

最后注意对n分解质因数要用pollard_rho。

#include<bits/stdc++.h>
#define M 70
#define N 110000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline ll read()
{
    char ch=0;
    ll x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
const ll mo=998244353;
ll rd(ll p){return rand()%p*rand()%p*rand()%p*rand()%p;}
ll ksc(ll x,ll y,ll p){return ((x*y-(ll)(((ldb)x*y+0.5)/p)*p)%p+p)%p;}
ll ksm(ll x,ll k,ll p){ll ans=1;while(k){if(k&1)ans=ksc(ans,x,p);k>>=1;x=ksc(x,x,p);}return ans;}
ll prime[N]={0,2,3,5,7,11,13,17,19,23};
bool miller_rabin(ll p)
{
    if(p<=1)return false;
    ll k=0,t=p-1;while(!(t&1))t>>=1,k++;
    for(ll i=1;i<=9;i++)
    {
        if(p==prime[i])return true;
        if(p%prime[i]==0)return false;
    }
    for(ll i=1;i<=9;i++)
    {
        ll x=ksm(prime[i],t,p),last;
        for(ll j=1;j<=k;j++)
        {
            last=x;x=ksc(x,x,p);
            if(x==1&&(last!=1&&last!=p-1))
            return false;
        }
        if(x!=1)return false;
    }
    return true;
}
set<ll>S;
set<ll>::iterator it;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll find(ll n)
{
    ll k=2,x=rd(n-1)+1,y=x,d=1,c=rd(n-1)+1;
    for(ll i=1;d==1;i++)
    {
        x=(ksc(x,x,n)+c)%n;
        d=gcd(abs(x-y),n);
        if(i==k)k<<=1,y=x;
    }
    return d;
}
void pollard_rho(ll n)
{
    if(n==1)return;
    if(miller_rabin(n))return (void)S.insert(n);
    ll t=n;
    while(t==n)t=find(n);
    pollard_rho(t);pollard_rho(n/t);
}
ll size;
struct matrix
{
    ll s[M][M];
    void clear(){memset(s,0,sizeof(s));}
}f,g;
matrix operator*(matrix a,matrix b)
{
    matrix ans;ans.clear();
    for(ll i=0;i<=size;i++)for(ll j=0;j<=size;j++)for(ll k=0;k<=size;k++)
    ans.s[i][j]=(ans.s[i][j]+(1ll*a.s[i][k]*b.s[k][j]%mo))%mo;
    return ans;
}
matrix E()
{
    matrix ans;ans.clear();
    for(ll i=0;i<=size;i++)ans.s[i][i]=1;
    return ans;
}
matrix pow(matrix x,ll k)
{
    matrix ans=E();
    while(k)
    {
        if(k&1)ans=ans*x;
        k>>=1;x=x*x; 
    }
    return ans;
}
int main()
{
    srand(time(0));
    ll n=read(),k=read()+1,ans=1;pollard_rho(n);
    for(it=S.begin();it!=S.end();it++)
    {
        ll x=n,o=*it;size=0;
        while(x%o==0)x/=o,size++;
        f.clear();f.s[0][size]=1;g.clear();
        for(ll i=0;i<=size;i++)for(ll j=0;j<=i;j++)g.s[i][j]=1;
        f=f*pow(g,k);
        ll t=0;
        for(ll i=0;i<=size;i++)t=(t+f.s[0][i])%mo;
        ans=1ll*ans*t%mo;
    }
    printf("%lld",ans);
    return 0;
}

以上是关于p4714 「数学」约数个数和的主要内容,如果未能解决你的问题,请参考以下文章

AcWing 1294. 樱花 数学推导+约数个数

反素数 -- 数学

算法最大公约数最小公倍数数学归纳法

codevs 2606 约数和(分块优化数学公式 )

1403 约数研究

BZOJ 1968 [Ahoi2005]COMMON 约数研究:数学思维题