4620. 【NOI2016模拟7.13】Jason做奥数

这里写图片描述

题解

题目要求n个范围在[1,L]的数任意排列的最小公倍数的和。
将每个数拆成 pk11pk22...pknn p 1 k 1 ∗ p 2 k 2 ∗ . . . ∗ p n k n 的形式,p为质因子。
现在就分别对每个质数计算。
考虑一个质数p,当它的次数为k的时候,有多少种可能。
那么就至少存在某个数的这个质数的次数为k,最大值必须为k。
于是方案数就是:
(l(l/(pk+1))n(l(l/pk))n) ( l − ( l / ( p k + 1 ) ) n − ( l − ( l / p k ) ) n )

现在就是计算的问题了,
对质数p进行分类,
当p< l l 的时候,就直接计算,枚举k。
当p> l l 的时候,很显然k只能为1。
式子就变为了:
(ln(l(l/p))n) ( l n − ( l − ( l / p ) ) n )
现在上面的系数只与l/p有关,
于是就可以直接分块做。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 5000003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(ll &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

bool bz[N];
ll ss[400000];

ll ksm(ll x,ll y,ll mo) 
{
    ll s=1;
    for(;y;y>>=1,x=x*x%mo)
        if(y&1)s=s*x%mo;
    return s;
}

void pre()
{
    memset(bz,1,sizeof(bz));
    for(int i=2;i<N;i++)
    {
        if(bz[i])ss[++ss[0]]=i;
        for(int j=1;j<=ss[0] && ss[j]*i<N;j++)
        {
            bz[i*ss[j]]=0;
            if(i%ss[j]==0)break;
        }
    }
}

ll n,m,l,p,T,w,s,t,ans;

int main()
{
    freopen("pupil.in","r",stdin);
    freopen("pupil.out","w",stdout);
    for(pre(),read(p),read(T);T;T--)
    {
        read(n);read(l);
        m=sqrt(l);ans=1;
        for(w=1;ss[w]<=m;w++)
        {
            s=ss[w];
            for(int k=1;s<=l;k++)
            {
                t=(ksm(l-l/(s*ss[w]),n,p-1)-ksm(l-l/s,n,p-1)+p-1)%(p-1);
                ans=ans*ksm(s,(t+p-1)%(p-1),p)%p;
                s=s*ss[w];
            }
        }

        for(s=ss[w],t=l/s,w++;ss[w]<=l;w++)
        {
            if(t==l/ss[w])s=s*ss[w]%p;else
            {
                ans=ans*ksm(s,(ksm(l,n,p-1)-ksm(l-t,n,p-1)+p-1)%(p-1),p)%p;
                s=ss[w];t=l/s;
            } 
        } 
        ans=ans*ksm(s,(ksm(l,n,p-1)-ksm(l-t,n,p-1)+p-1)%(p-1),p)%p;

        write(ans),P('\n');
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值