哈老师抄来的比赛之心灵治愈

【问题描述】
给出一个方程:
A1 * X1` + A2 * X2 + …… + An+1 * Xn+1 = 1
其中 Xn+1 为 m,其余的 X 可以为小于等于 m 的任意的正整数,A 可以取任意的整数。
现在的问题是,给出 n 与 m,需要你求出该方程解的方案数,对 1e9+7 取模。
【输入格式】
给出两个数 N 与 M。
【输出格式】
输出一个方案数。
【样例输入 1】
2 3
【样例输出 1】
8
【样例解释 1】
(1, 1, 3), (1, 2, 3), (1, 3, 3), (2, 1, 3),
(2, 2, 3), (2, 3, 3), (3, 1, 3), (3, 2, 3).
【样例输入 2】
8 8
【样例输出 2】
16711680

当时考试的时候完全没有思路QAQ
实际上我们要先知道一个结论,就是当且仅当gcd(x1,x2,x3,x4……..xn,m)=1的时候是有解的
先证明一下吧:
首先,我们要是gcd不等于1,那么肯定是不行的,因为你怎么弄,最后的差肯定是gcd的倍数
所以问题就只剩下gcd=1的时候为什么可行
考虑使用费马小定理
然后胡乱证明一通就好了
当然,有一个问题,就是需要p是质数,这没有关系,我们只要从x中任意拿出一个质数a,然后吧x/a扔到系数里面就好了

知道这个结论就好做了
我们考虑容斥原理,不会的可以去看我的另一篇博客
枚举一下gcd是什么的倍数是什么就好了

#include<cstdio>
#include<cstdlib>
typedef long long LL;
const LL N=100005;
const LL MOD=1e9+7;
LL get(LL a, LL e) {
    LL ret, cnt; 
    ret = 1; 
    cnt = a % MOD; 
    while(e) {
        if(e&1) ret = ret * cnt % MOD; 
        cnt = cnt * cnt % MOD; 
        e >>= 1; 
    }
    return ret; 
}
LL pri[N],now=0;
void shen (LL mm)
{
    for (LL u=2;u*u<=mm;u++)
        if (mm%u==0)
        {
            pri[++now]=u;
            while (mm%u==0) mm/=u;
        }
    if (mm!=1) pri[++now]=mm;
    return ;
}
LL ans=0;
LL n,m;
void ooo (LL x,LL y,LL num)//我现在选到第几个数     现在选用了多少个     选到数的积
{
    if (x>now)
    {
        if (y%2!=0) ans=(ans-get(num,n)%MOD)%MOD;
        else ans=(ans+get(num,n)%MOD)%MOD;
        return ;
    }
    ooo(x+1,y,num);
    ooo(x+1,y+1,num/pri[x]);
}
int main()
{
    freopen("heal.in","r",stdin);
    freopen("heal.out","w",stdout);
    scanf("%I64d%I64d",&n,&m);
    if (n==0)
    {
        printf("%d\n",(m==1||m==-1));
        return 0;
    }
    shen(m);
    ooo(1,0,m);
    printf("%I64d\n",(ans+MOD)%MOD);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值