洛谷 P2480 [SDOI2010]古代猪文 题解【欧拉定理】【CRT】【Lucas定理】

数论综合题。

题目背景

题目背景与题目无关因此省略。题目链接

题目描述

猪王国的文明源远流长,博大精深。

iPig 在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为 \(N\)。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。

iPig 打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的 \(k\) 分之一,其中 \(k\)\(N\) 的一个正约数(可以是 \(1\)\(N\))。不过具体是哪 \(k\) 分之一,以及 \(k\) 是多少,由于历史过于久远,已经无从考证了。

iPig 觉得只要符合文献,每一种能整除 \(N\)\(k\) 都是有可能的。他打算考虑到所有可能的 \(k\)。显然当 \(k\) 等于某个定值时,该朝的猪文文字个数为 \(\frac Nk\)。然而从 \(N\) 个文字中保留下 \(\frac Nk\) 个的情况也是相当多的。iPig 预计,如果所有可能的 \(k\) 的所有情况数加起来为 \(P\) 的话,那么他研究古代文字的代价将会是 \(G\)\(P\) 次方。

现在他想知道猪王国研究古代文字的代价是多少。由于 iPig 觉得这个数字可能是天文数字,所以你只需要告诉他答案除以 \(999911659\) 的余数就可以了。

输入输出格式

输入格式:

输入有且仅有一行:两个数 \(N,G\),用一个空格分开。

输出格式:

输出有且仅有一行:一个数,表示答案除以 \(999911659\) 的余数。

输入输出样例

输入样例#1:

4 2

输出样例#1:

2048

说明

\(10\%\) 的数据中,\(1\le N\le 50\)

\(20\%\) 的数据中,\(1\le N\le 10^3\)

\(40\%\) 的数据中,\(1\le N\le 10^5\)

\(100\%\) 的数据中,\(1\le G\le 10^9,1\le N\le 10^9\)

题解

题意即给定 \(N,G\),求
\[ G^{\sum_{d|n}\mathrm C_n^d}\bmod 999911659 \]
\(G\bot 999911659\) (二者互质)时,指数方面可以用欧拉定理化为 \(\sum_{d|n}\mathrm C_n^d\bmod 999911658\)

\(999911659\) 是质数,所以 \(\varphi(999911659)=999911658\),当且仅当 \(G=999911659\) 时不成立,此时原式恒为 \(0\),注意这里要特判。

而满足 \(d|n\) 的数最多只有 \(O(\log n)\) 个,这样的枚举也最多只进行了 \(O(\sqrt n)\) 次,问题的关键就转到了如何快速求出 \(\mathrm C_n^d\) 上了。

我们知道,当模数为质数时,可以使用 Lucas 定理来做到 \(O(\log p)\) 求出组合数模 \(p\) 意义下的结果,且空间复杂度最小为 \(O(p)\)。此时既不满足模数为质数,也无法满足空间需求。

考虑质因数分解 \(999911658​\) 这个数字,得到 \(2\times 3\times 4679\times 35617​\),它的质因数的次数都是 \(1​\)。利用这个性质我们可以做什么呢?

\(\mathrm C_n^d\equiv x\pmod{999911658}\),由于 \(999911658\) 有上面四个质因数,所以把
\[ \left\{ \begin{aligned} x\equiv a_1&\pmod 2\\\ x\equiv a_2&\pmod 3\\\ x\equiv a_3&\pmod {4679}\\\ x\equiv a_4&\pmod {35617} \end{aligned} \right. \]
这个方程组合并,会得到 \(x\equiv a\pmod{999911658}\)\(a\) 就是我们要求的答案了。

而根据 Lucas 定理,上面那四个模数都是质数,所以可以求出 \(a_1,a_2,a_3,a_4\),最后用 CRT 合并一下就可以了。

时间复杂度 \(O(\log^2n)\)。(分别是求 \(d\) 的复杂度和 Lucas 定理的复杂度)

一定要特判 \(G=999911658\)

Code:

#include<cstdio>
#include<cstring>
#define ll long long
ll fact[40000],inv[40000],p;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    ll g=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return g;
}
ll qpow(ll x,ll y)
{
    ll ans=1;
    while(y)
    {
        if(y&1)
            ans=ans*x%p;
        x=x*x%p;
        y>>=1;
    }
    return ans;
}
ll qmul(ll x,ll y)
{
    ll ans=0;
    if(x<0)
        x=p+x;
    if(y<0)
        y=p+y;
    while(y)
    {
        if(y&1)
            ans=(ans+x)%p;
        x=(x+x)%p;
        y>>=1;
    }
    return ans;
}
ll C(ll n,ll m)
{
    if(n<m)
        return 0;
    if(n<p&&m<p)
        return fact[n]*inv[m]%p*inv[n-m]%p;
    return C(n/p,m/p)*C(n%p,m%p)%p;
}
int d[1000],cnt=0;
ll a[5],b[5]={0,2,3,4679,35617};
int main()
{
    ll n,g,x,y;
    scanf("%lld%lld",&n,&g);
    if(g==999911659)
    {
        puts("0");
        return 0;
    }
    for(int i=1;i*i<=n;++i)
        if(n%i==0)
        {
            d[++cnt]=i;
            if(i*i!=n)
                d[++cnt]=n/i;
        }
    //先算 T%2
    for(int l=1;l<=4;++l)
    {
        p=b[l];
        fact[0]=1;
        for(int i=1;i<p;++i)
            fact[i]=fact[i-1]*i%p;
        inv[p-1]=qpow(fact[p-1],p-2);
        for(int i=p-2;i>=0;--i)
            inv[i]=inv[i+1]*(i+1)%p;
        for(int i=1;i<=cnt;++i)
            a[l]=(a[l]+C(n,d[i]))%p;
    }
    for(int i=2;i<=4;++i)
    {
        ll g=exgcd(b[i],b[i-1],x,y);
        p=b[i-1]/g;
        x=qmul(x,(a[i]-a[i-1])/g);
        p*=b[i];
        a[i]-=qmul(x,b[i]);
        a[i]=(a[i]%p+p)%p;
        b[i]=p;
    }
    p=999911659;
    printf("%lld\n",qpow(g,(a[4]%b[4]+b[4])%b[4]));
    return 0;
}

转载于:https://www.cnblogs.com/wjyyy/p/lg2480.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述似乎缺失了关键信息,通常我会需要了解“P10780 食物”是什么具体的算法竞赛题目,它来自在线平台洛谷Luogu),以及该题目的大致背景、条件和目标。洛谷食物(Food)可能是某种数据结构或算法问题,比如贪吃蛇、分配任务等。 然而,我可以给你提供一个通用的模板: **[洛谷 P10780 食物 - 题目解析]** 题目名称:P10780 食物(假设是关于食物分配或者饥饿游戏的问题) 链接:[插入实际题目链接] **背景:** 此题通常涉及动态规划或者搜索策略。场景可能是有n个参与者(选手或角色),每个都有特定的食物需求或者优先级,我们需要在有限的食物资源下合理分配。 **分析:** 1. **输入理解**:首先读入n个参与者的信息,包括每个人的需求量或优先级。 2. **状态定义**:可以定义dp[i][j]表示前i个人分配完成后剩余的食物能满足第j个人的最大程度。 3. **状态转移**:递推式可能涉及到选择当前人分配最多食物的版本,然后更新剩余的食物数。 4. **边界条件**:如果剩余食物不足以满足某人的需求,则考虑无法分配给他;如果没有食物,状态值设为0。 5. **优化策略**:可能需要对状态数组进行滚动更新,以减少空间复杂度。 **代码示例(伪代码或部分关键代码片段):** ```python # 假设函数分配_food(demand, remaining)计算分配给一个人后剩余的食物 def solve(foods): dp = [[0 for _ in range(max_demand + 1)] for _ in range(n)] dp = foods[:] # 从第一个到最后一个参与者处理 for i in range(1, n): for j in range(1, max_demand + 1): if dp[i-1][j] > 0: dp[i][j] = max(dp[i][j], dp[i-1][j] - foods[i]) dp[i][j] = max(dp[i][j], distribute_food_to(i, dp[i-1][j])) return dp[n-1][max_demand] ``` **相关问题--:** 1. 这道题是如何运用动态规划的? 2. 如果有优先级限制,应该如何调整代码? 3. 怎样设计搜索策略来解决类似问题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值