CF900D Unusual Sequences
CF900D Unusual Sequences
一开始看数据范围好像没什么思路
后来机房大佬提醒可以反演
首先如果y不是x的倍数,那么直接输出0
不然就 y /= x,求gcd为1的序列个数
设
g
(
x
)
为
和
为
x
,
没
有
限
制
的
序
列
个
数
设g(x)为和为x,没有限制的序列个数
设g(x)为和为x,没有限制的序列个数
x
个
1
,
有
x
−
1
个
空
,
即
序
列
个
数
g
(
x
)
=
2
x
−
1
x个1,有x-1个空,即序列个数g(x)=2^{x-1}
x个1,有x−1个空,即序列个数g(x)=2x−1
再
设
f
(
x
)
为
和
为
x
,
g
c
d
为
1
的
序
列
个
数
再设f(x)为和为x,gcd为1的序列个数
再设f(x)为和为x,gcd为1的序列个数
显
然
g
(
x
)
=
∑
d
∣
x
f
(
d
)
显然g(x)=\sum\limits_{d|x}f(d)
显然g(x)=d∣x∑f(d)
这个随便想想gcd就能推出来
这一步可以直接反演,也可以移一下项,然后继续推
f
(
x
)
=
g
(
x
)
−
∑
d
∣
x
,
d
>
1
f
(
x
/
d
)
f(x)=g(x) - \sum\limits_{d|x, d > 1}f(x / d)
f(x)=g(x)−d∣x,d>1∑f(x/d)
然后直接递推即可
然而递推的复杂度不太会算
好像是
O
(
d
(
n
)
l
o
g
n
)
O(d(n)logn)
O(d(n)logn)的
#include<bits/stdc++.h>
#define mod 1000000007
#define int long long
using namespace std;
int qpow(int x, int y) {
int ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
map<int, int> ff;
int f(int n) {
if(n == 1) return 1;
if(ff[n]) return ff[n];
ff[n] = qpow(2, n - 1);
ff[n] = (ff[n] - f(1) + mod) % mod;
for(int i = 2; i * i <= n; i ++) if(n % i == 0) {
ff[n] = (ff[n] - f(i) + mod) % mod;
if(i * i != n)
ff[n] = (ff[n] - f(n / i) + mod) % mod;
}
return ff[n];
}
int x, y;
signed main() {
scanf("%lld%lld", &x, &y);
if(y % x != 0) printf("0");
else {
y /= x;
printf("%lld", f(y));
}
return 0;
}
这种套路还是挺常见的