【题解】SDOI2008莎拉公主的困惑

挺有趣的恩:洛谷P2155

在纸上打打草稿,写出n!个数,从先往后,遇到不互质的就筛掉——发现一个奇妙的性质!:筛掉的次数、顺序好像是周期性出现的呢~

而且更加妙妙的是,好像还是m!一轮..那么因为n!一定能被m!整除,所以问题转变为:(n!\m! - 有多少个循环节)*(φ(m))。

接下来,φ(m) = m!*(1 - 1/p1)*(1 - 1/p2)...任务就只剩下打出阶乘表&逆元啦。离线的处理会快很多。

#include <bits/stdc++.h>
using namespace std;
#define maxn 10000050
#define ll long long
#define int long long
int maxx, now = 1, P, T, tot, inv[maxn], ans[10050], pri[maxn],fac_a[maxn], fac_b[maxn], fac_c[maxn];
bool is_prime[maxn];
struct query
{
    int n, m, id, pri;
}Q[10050];

int read()
{
    int x = 0;
    char c;
    c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

bool cmp1(query a, query b)
{
    return a.m < b.m;
}

int Get_Pri(int n)
{
    for(int i = 2; i <= n; i ++)
    {
        if(!is_prime[i])
        {
            pri[++ tot] = i;
            while(now <= T && pri[tot] > Q[now].m)
            {
                Q[now].pri = tot - 1;
                now ++;
            }  
        }
        while(now <= T && i == n)
            {
                Q[now].pri = tot;
                now ++;
            }
        for(int j = 1; j <= tot; j ++)
        {
            if(i * pri[j] > n) break;
            is_prime[i * pri[j]] = 1;
            if(!(i % pri[j])) break;
        }
    }
}

int Get_fac(int n)
{
    fac_a[0] = fac_a[1] = fac_b[0] = fac_b[1] = fac_c[0] = fac_c[1] = 1;
    inv[0] = inv[1] = 1;
     for(int i = 2; i <= n; i ++)
     {
         fac_a[i] = (fac_a[i - 1] * i) % P;
        inv[i] = ((P - P / i) * inv[P % i]) % P;
    }
    for(int i = 1; i <= tot; i ++)
    {
        fac_b[i] = inv[pri[i]];
        fac_b[i] = (fac_b[i] * fac_b[i - 1]) % P;
        fac_c[i] = pri[i] - 1;
        fac_c[i] = (fac_c[i] * fac_c[i - 1]) % P;
    }
}

signed main()
{
    T = read(), P = read();
    for(int i = 1; i <= T; i ++)
    {
        Q[i].n = read(), Q[i].m = read(), Q[i].id = i;
        maxx = max(maxx, max(Q[i].n, Q[i].m));
    }
    sort(Q + 1, Q + 1 + T, cmp1);
    Get_Pri(maxx);
    Get_fac(maxx);
    for(int i = 1; i <= T; i ++)
        ans[Q[i].id] = ((fac_a[Q[i].n] * fac_b[Q[i].pri]) % P * fac_c[Q[i].pri]) % P;
    for(int i = 1; i <= T; i ++)
        printf("%lld\n", ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/twilight-sx/p/8416225.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值