数论好题 CF900D

前置推导

b1=a1x,b2=a2x,,bn=anx

很显然 bi 为整数,且 b 数组的全部元素互质,即 gcd(b1,b2,b3,,bn)=1

因为

i=1nai=y

所以

x×i=1nbi=y

i=1nbi=yx

根据 + = 的封闭法则且 bi 为整数,可得 yx 也是整数。所以当 xy 时一定无解。

m=yx,则

i=1nbi=m

大致思路

我们现在的目标是求出 b 数组,满足所有元素互质。直接这样看上去很难求,我们考虑正难则反,利用容斥原理解决,即先假设 b 数组中的元素不一定满足两两互质的个数,然后计算出 gcd(b1,b2,,bn)=dd1 的个数。再用总个数减去不满足条件的个数就是满足条件的个数。

总个数

先来计算总个数,显然我们当前求解的问题相当于求 m 的所有本质不同的拆分总方案数。

因为

m=1+1++1m

所以可以考虑插板法,设当前要把 m 拆为 i 个数相加,所以此时方案数为(m1i1)

方法 1(暴力)

所以总方案数为

i=1m(m1i1)

根据二项式定理

(a+b)n=i=0n(ni)×ani×bi

a=1,b=1

i=0m1(m1i)×1×1=i=1m(m1i1)

所以

i=1m(m1i1)=(1+1)m1=2m1

方法 2(人类智慧)

因为空位只有选和不选两种情况,一共有 m1 个空位,所以总方案数为 2m1

不满足条件的个数

令函数 f(x) 表示 i=1nbi=xgcd(b1,b2,b3,,bn)=1 的个数。考虑怎么递推 f(x),我们很容易地发现和为 mgcd(b1,b2,b3,,bn)=d 的个数为 f(md)显然 d|m

所以

d|xf(xd)=2x1

再根据容斥原理得

f(x)=2x1d|x,d1f(xd)

f(x)=2x1d|x,dxf(d)

求解

递归求解 f(x) 即可。

时间复杂度 O(n)

Code

#include <bits/stdc++.h>
#define int long long
#define Add(x, y) x = add(x, y)
#define Mul(x, y) x = mul(x, y)

std :: map <int, int> ans;
int x, y; const int mod = 1e9 + 7;
int mul(int x, int y) { return x * y % mod; }
int add(int x, int y) { return (x + y) % mod; }

int qpow(int x, int y) {
	int ans = 1;  while(y) {
		if(y & 1) ans = mul(ans, x);
		x = mul(x, x), y >>= 1;
	} return ans;
}

int calc(int o) {
	if(o == 1) return 1;
	if(ans[o]) return ans[o];
	int res = calc(1); 
	for(int i = 2; i * i <= o; ++ i) {
		if(o % i) continue;
		Add(res, add(calc(i), (i * i != o) * calc(o / i))); 
	} return ans[o] = add(qpow(2, o - 1), -res);
}

signed main() {
	scanf("%lld%lld", &x, &y);
	if(y % x) return puts("0"); 
	printf("%lld", add(mod, calc(y / x)));
}
posted @   wangyuanbo  阅读(26)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示