组合和

题目大意

ni=1Cm(i,n)

做法

随手化一下式子变成
d|nCmdϕ(nd)
发现很想狄利克雷卷积的形式,不妨尝试凑出另一个积性函数。
1m!d|nmi=0s(m,i)(1)midiϕ(nd)
1m!mi=0s(m,i)(1)mid|ndiϕ(nd)
现在就好了!
两个积性函数狄利克雷卷积还是积性函数。
gi(n)=d|ndiϕ(nd)
答案是1m!mi=0s(m,i)(1)miΠpk|ngi(pk)
考虑计算质数的次幂。
gi(pk)=kj=0pijϕ(pkj)
gi(pk)=(p1)k1j=0pk1+(i1)j+pik
分解质因数用pollard_rho。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=3000+10,mo=1998585857;
ll ss[maxn][maxn];
ll p[maxn],c[maxn];
ll i,j,k,l,t,n,m,tot,top,ans,num;
ll qsm(ll x,ll y){
    if (!y) return 1;
    ll t=qsm(x,y/2);
    t=t*t%mo;
    if (y%2) t=t*x%mo;
    return t;
}
ll calcg(ll i,ll p,ll k){
    ll j,t=0;
    fo(j,0,k-1) (t+=qsm(p%mo,k-1+(i-1)*j))%=mo;
    t=t*((p-1)%mo)%mo;
    (t+=qsm(p%mo,i*k))%=mo;
    return t;
}
ll random(ll x){
    ll t=rand()%10000;
    t=t*10000+rand()%10000;
    t=t*10000+rand()%10000;
    t=t*10000+rand()%10000;
    return t%x;
}
ll mul(ll a,ll b,ll p){
    ll tmp=(a*b-(ll)((long double)a/p*b+1e-8)*p);
    return tmp<0?tmp+p:tmp;
}
ll quicksortmi(ll x,ll y,ll mo){
    if (!y) return 1;
    ll t=quicksortmi(x,y/2,mo);
    t=mul(t,t,mo);
    if (y%2) t=mul(t,x,mo);
    return t;
}
bool Miller_Rabin(ll n){
    if (n==1) return 0;
    int s=5,t=0,i;
    ll a,p,k=n-1;
    while (k%2==0) k/=2,t++;
    while (s--){
        a=random(n-1)+1;
        p=a=quicksortmi(a,k,n);
        fo(i,1,t){
            a=mul(a,a,n);
            if (a==1&&p!=1&&p!=n-1) return 0;
            p=a;
        }
        if (a!=1) return 0;
    }
    return 1;
}
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll Pollard_Rho(ll n){
    ll k,x,y,c,d,i=1;
    while (1){
        c=random(n-1);
        k=2;y=x=random(n);
        i=1;
        while (1){
            y=(mul(y,y,n)+c)%n;
            d=gcd(abs(x-y),n);
            if (i==k) x=y,k<<=1;
            i++;
            if (d!=1) break;
        }
        if (d!=n) return d;
    }
}
void work(ll n){
    if (Miller_Rabin(n)){
        //ans=max(ans,n);
        p[++top]=n;
        return;
    }
    ll p=Pollard_Rho(n);
    ll q=n/p;
    work(p);work(q);
}
int main(){
    freopen("sum.in","r",stdin);freopen("sum.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    ss[0][0]=1;
    fo(i,1,m){
        fo(j,1,i) ss[i][j]=(ss[i-1][j-1]+ss[i-1][j]*(i-1)%mo)%mo;
    }
    /*t=floor(sqrt(n));
    k=n;
    fo(i,2,t)
        while (k%i==0){
            p[++top]=i;
            k/=i;
        }
    if (k>1) p[++top]=k;*/
    work(n);
    sort(p+1,p+top+1);
    tot=top;
    top=0;
    fo(i,1,tot)
        if (p[i]!=p[i-1]){
            p[++top]=p[i];
            c[top]=1;
        }
        else c[top]++;
    fo(i,0,m){
        num=1;
        fo(j,1,top) num=num*calcg(i,p[j],c[j])%mo;
        num=num*ss[m][i]%mo;
        if ((m-i)%2) (ans-=num)%=mo;else (ans+=num)%=mo;
    }
    fo(i,1,m) ans=ans*qsm(i,mo-2)%mo;
    (ans+=mo)%=mo;
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值