【51NOD 1965】奇怪的式子

Description

i=1nσ0(i)i+μ(i)mod(1012+39) ∏ i = 1 n σ 0 ( i ) i + μ ( i ) mod ( 10 12 + 39 )

σ(i) σ ( i ) 表示i的约数个数

Solution

本题要用Min_25筛
本题要用LL*LL取模,恶心…

考虑把答案拆成两半计算: ni=1σ0(i)ini=1σ0(i)μ(i) ∏ i = 1 n σ 0 ( i ) i ∗ ∏ i = 1 n σ 0 ( i ) μ ( i )
先考虑前半部分怎么处理:

显然的结论:设 x=pcjj x = ∏ p j c j ,p为互不相同的质数
σ0(i)=(cj+1) σ 0 ( i ) = ∏ ( c j + 1 )
那我们答案就是:(设 Sum(x)=(x+1)x/2 S u m ( x ) = ( x + 1 ) x / 2

i=1nσ0(i)i=i=1k=1(k+1)pkiSum(npki)pk+1iSum(npk+1i) ∏ i = 1 n σ 0 ( i ) i = ∏ i = 1 ∏ k = 1 ( k + 1 ) p i k ∗ S u m ( ⌊ n p i k ⌋ ) − p i k + 1 ∗ S u m ( ⌊ n p i k + 1 ⌋ )

对于小于 n n 的质数直接计算,对于大于的 n n 质数,k只能等于1,

暴力的做法:直接设 S(n,j)=ni=2[iipj]Sum(ni) S ( n , j ) = ∑ i = 2 n [ i 为 质 数 或 i 的 最 小 质 因 子 大 于 p j ] ∗ S u m ( ⌊ n i ⌋ )

正确做法: S(n,j)=ni=2[iipj]i S ( n , j ) = ∑ i = 2 n [ i 为 质 数 或 i 的 最 小 质 因 子 大 于 p j ] ∗ i
也就是直接筛质数,做后计算答案的时候再分块一下即可

对于后面的部分,显然的,每个质数最多出现一次,这个直接设 F(n,j)=ni=2[iipj]μ(i)(i) F ( n , j ) = ∑ i = 2 n [ i 为 质 数 或 i 的 最 小 质 因 子 大 于 p j ] ∗ μ ( i ) ∗ ( i 的 质 因 子 个 数 )
还要设一个 F1(n,j)=ni=2[iipj]μ(i) F 1 ( n , j ) = ∑ i = 2 n [ i 为 质 数 或 i 的 最 小 质 因 子 大 于 p j ] ∗ μ ( i ) 来辅助转移,

F(n,j)=F(n,j+1)(F(npj,j+1)j)(F1(npj,j+1)j) F ( n , j ) = F ( n , j + 1 ) − ( F ( ⌊ n p j ⌋ , j + 1 ) − j ) − ( F 1 ( ⌊ n p j ⌋ , j + 1 ) − j )

F1(n,j)=F1(n,j+1)(F1(npj,j+1)j) F 1 ( n , j ) = F 1 ( n , j + 1 ) − ( F 1 ( ⌊ n p j ⌋ , j + 1 ) − j )

复杂度: O(n34) O ( n 3 4 )

Code

#include <cstdio>
#include <algorithm>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=706000;
const LL mo=1e12+39;
const LL mo1=1e12+38;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int M;
LL n,ans;
int pr[N];
LL prs[N],prf[N];
bool prz[N];
LL chen(LL q,LL w,LL mo11=mo)
{
    q%=mo11;w%=mo11;
    LL tmp=(LL)((long double)q*w/mo11+1e-8)*mo11;
    return (q*w-tmp+mo11)%mo11;
}
LL SUM(LL n,LL mo1=mo)
{
    if(n<1e9)
    {
        return (n&1)?(((n+1)>>1)*n%mo1):((n>>1)*(n+1LL)%mo1);
    }
    return (n&1)?chen(((n+1)>>1),n,mo1):chen((n>>1),(n+1LL),mo1);
}
void Pre(int n)
{
    fo(i,2,n)
    {
        if(!prz[i])pr[++pr[0]]=i,prs[pr[0]]=(prs[pr[0]-1]+pr[pr[0]])%mo1;
        fo(j,1,pr[0])
        {
            int t=i*pr[j];
            if(t>n)break;
            prz[t]=1;
            if(i%pr[j]==0)break;
        }
    }
}
LL ksm(LL q,LL w)
{
    LL ans=1;
    w=(w%mo1+mo1)%mo1;
    for(;w;w>>=1,q=chen(q,q))
        if(w&1)ans=chen(ans,q);
    return ans;
}
LL f[N];
LL d[N];
int id[N],id1[N];
LL g[N],g1[N];
void GS(LL n)
{
    d[0]=0;
    for(LL i=1,nx;i<=n;i=nx+1)
    {
        nx=n/(n/i);
        LL t=n/i;
        d[++d[0]]=t;
        f[d[0]]=SUM(t,mo1)-1;
        g[d[0]]=t-1;
        if(t<=M)id[t]=d[0];
        else id1[n/t]=d[0];
    }
    fo(j,1,pr[0])
    {
        LL li=(LL)pr[j]*pr[j];
        for(int i=1;d[i]>=li;++i)
        {
            LL t1=d[i]/pr[j];
            int t=(t1>M)?id1[n/t1]:id[t1];
            f[i]=(f[i]-(f[t]-prs[j-1])*(LL)pr[j])%mo1;
            g[i]=(g[i]-(g[t]-j+1))%mo1;
        }
    }
    fo(i,1,d[0])if(d[i]>pr[pr[0]])f[i]=(f[i]-prs[pr[0]])%mo1;else f[i]=0;
    LL t=0;
    fo(i,1,d[0])if(d[i]>pr[pr[0]])t=(t+chen((f[i]-f[i+1]),SUM(n/d[i],mo1),mo1))%mo1;
    ans=chen(ans,ksm(2,t));
    fo(i,1,d[0])g1[i]=g[i]=mo1-g[i];
    fod(j,pr[0],1)
    {
        LL li=(LL)pr[j]*pr[j];
        for(int i=1;d[i]>=li;++i)
        {
            LL t1=d[i]/pr[j];
            int t=(t1>M)?id1[n/t1]:id[t1];
            g[i]=(g[i]-(g[t]+j)-(g1[t]+j))%mo1;
            g1[i]=(g1[i]-(g1[t]+j))%mo1;
        }
    }
    g[1]=(g[1]+mo1)%mo1;
    ans=chen(ans,ksm(2,g[1]));
}
void Doit()
{
    ans=1;
    fo(i,1,pr[0])prf[i]=pr[i];
    fo(i,1,64)
    {
        LL t=0;
        fo(j,1,pr[0])
        {
            if(n<prf[j])break;
            t=(t+(SUM(n/prf[j],mo1)-pr[j]*SUM(n/(prf[j]*pr[j]),mo1))%mo1*prf[j])%mo1;
            prf[j]*=pr[j];
        }
        ans=chen(ans,ksm(i+1,t));
    }
    GS(n);
    printf("%lld\n",ans);
}
int main()
{
    int _;
    M=500000;
    Pre(M);
    scanf("%d",&_);
    while(_--)
    {
        scanf("%lld",&n);
        Doit();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值