【问题描述】
给出一个方程:
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;
}