JZOJ 5348. 【NOIP2017提高A组模拟9.5】心灵治愈
题目大意
求 \(b\) (正整数集合)使得 \(\sum_{i=1}^{n+1} a_i \times b_i = 1\)
其中给定 \(b_{n+1}=m\) 且为 \(b\) 中最大值
\(1 \leq n,m \leq 10^{15}\)
解法
其实很简单
很容易想到 \(\gcd(b_1,b_2,...,b_{n+1}) = 1\)
而 \(b_{n+1}=m\) 为最大值
那么我们就可以构造满足 \(\gcd\) 两两互质的数列,则必满足题目要求(裴蜀定理)
于是我们要怎么算?
正难则反
我们算不满足的数列的个数
只要这些数的最大公约数大于 \(1\) 则可
我们把 \(m\) 分解质因数
每个质因子 \(\alpha\),\(m\) 内就有 \(m / \alpha\) 个数是其倍数
全这些数来构造数列,必然不合法,有 \((m / \alpha) ^ n\) 个
但我们会算重,容斥即可
总的方案有 \(m^n\) 个,减去这些不合法的即可
\(Code\)
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
const LL P = 1e9 + 7;
int cnt , ct;
LL n , m , num[30] , tmp[30] , c[30] , ans;
void dfs(int x , LL s , int b)
{
if (x > cnt)
{
tmp[++ct] = s , c[ct] = (b & 1 ? -1 : 1);
return;
}
dfs(x + 1 , s * num[x] , b + 1);
dfs(x + 1 , s , b);
}
LL fpow(LL x , LL y)
{
LL res = 1;
x %= P;
while (y)
{
if (y & 1) res = res * x % P;
y >>= 1 , x = x * x % P;
}
return res;
}
int main()
{
freopen("heal.in" , "r" , stdin);
freopen("heal.out" , "w" , stdout);
scanf("%lld%lld" , &n , &m);
LL o = m;
for(register int i = 2; (LL)i * i <= o; i++)
if (o % i == 0)
{
num[++cnt] = i;
while (o % i == 0) o /= i;
}
if (o > 1) num[++cnt] = o;
dfs(1 , 1 , 0);
for(register int i = 1; i <= ct; i++)
{
o = fpow(m / tmp[i] , n);
ans = ((ans + o * c[i]) % P + P) % P;
}
printf("%lld" , ans);
}