L3-030 可怜的简单题

九条可怜去年出了一道题,导致一众参赛高手惨遭团灭。今年她出了一道简单题 —— 打算按照如下的方式生成一个随机的整数数列 A:

  1. 最开始,数列 A 为空。

  2. 可怜会从区间 [1,n] 中等概率随机一个整数 i 加入到数列 A 中。

  3. 如果不存在一个大于 1 的正整数 w,满足 A 中所有元素都是 w 的倍数,数组 A 将会作为随机生成的结果返回。否则,可怜将会返回第二步,继续增加 A 的长度。

现在,可怜告诉了你数列 n 的值,她希望你计算返回的数列 A 的期望长度。

输入格式:

输入一行两个整数 n,p (1≤n≤10^11,n<p≤10^12),p 是一个质数。

输出格式:

在一行中输出一个整数,表示答案对 p 取模的值。具体来说,假设答案的最简分数表示为 yx​,你需要输出最小的非负整数 z 满足 y×z≡x mod p。

输入样例 1:

2 998244353

输出样例 1:

2

输入样例 2:

100000000 998244353

输出样例 2:

3056898

代码长度限制

16 KB

时间限制

10000 ms

内存限制

512 MB

由于本人能力、时间有限,仅给出最后表达式。

 

 

还有一些相乘有一些会爆long long   。。。。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e7+10;
const int M=2e7;
int n,mod;
int prime[N];
int mu[N];
bool vis[N];
int cnt;
unordered_map<int,int>sum_mu;
void init()
{
    mu[1]=1;

    for(int i=2; i<=M; i++)
    {
        if(vis[i]==0)
        {
            prime[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1; j<=cnt&&i*prime[j]<=M; j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1; i<=M; i++)
    {
        mu[i]+=mu[i-1];
    }
}

inline int f1(int x)
{

    if(x<=M)
        return mu[x];

    if(sum_mu[x])
        return sum_mu[x];

    int ans=1;
    for(int l=2,r; l<=x; l=r+1)
    {

        r=x/(x/l);

        ans-=(r-l+1)*f1(x/l);

    }

    return sum_mu[x]=ans;

}
int qmul(int a,int b)
{
    return (__int128)a*b%mod;
}
int qmi(int a,int b)
{
    int res = 1;
    while (b)
    {
        if (b & 1) res = qmul(res, a);
        a = qmul(a, a);
        b >>= 1;
    }
    return res;
}
void solve()
{
    cin>>n>>mod;
    int res = 1;
    for (int l = 2, r; l <= n; l = r + 1)
    {
        r = n / (n / l);
        int t = qmul(n / l, qmi(n - n / l, mod - 2));
        res = (res - qmul(f1(r) - f1(l - 1), t) + mod) % mod;
    }
    cout << res << "\n";

}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    init();

    int T;
    T=1;
    while(T--)
    {
        solve();
    }
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值