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);
} 
posted @ 2020-10-10 13:35  leiyuanze  阅读(70)  评论(0编辑  收藏  举报