Problem Statement
You have a sequence S of small positive integers. You want to erase some (possibly none but not all) elements of S in such a way that the greatest common divisor of the resulting sequence becomes exactly goal.
Let W be the number of ways in which the above can be done. Compute and return the value (W modulo (10^9 + 7)).
Definition
Class: EraseToGCD
Method: countWays
Parameters: vector , int
Returns: int
Method signature: int countWays(vector S, int goal)
(be sure your method is public)
Limits
Time limit (s): 2.000
Memory limit (MB): 256
Notes
Two ways of erasing are different if the sets of indices of erased elements differ.
Constraints
S will have between 1 and 500 elements, inclusive.
Each element of S will be between 1 and 1000, inclusive.
goal will be between 1 and 1000, inclusive.
为什么这样的套路题还可以原封不动的出出来。
设
f
[
i
]
f[i]
f[i]为答案,即
g
c
d
gcd
gcd为
i
i
i的组合有多少个,这个东西不太好求。
根据套路,要大力容斥。
设
g
[
i
]
g[i]
g[i]为
g
c
d
gcd
gcd为
i
i
i的倍数的组合的个数
那么有
f
[
i
]
=
g
[
i
]
−
∑
i
∣
d
且
i
!
=
d
g
[
d
]
f[i]=g[i]-\sum_{i|d 且 i != d}g[d]
f[i]=g[i]−i∣d且i!=d∑g[d]
g
[
i
]
g[i]
g[i]就比
f
[
i
]
f[i]
f[i]好求了。
设
a
[
i
]
a[i]
a[i]为数字为
i
i
i的数字有多少个,
h
[
i
]
h[i]
h[i]为数字为
i
i
i的倍数的数字有多少个。
那么有
h
[
i
]
=
∑
i
∣
d
a
[
d
]
h[i]=\sum_{i|d}a[d]
h[i]=i∣d∑a[d]
这样就有
g
[
i
]
=
2
h
[
i
]
−
1
g[i]=2^{h[i]}-1
g[i]=2h[i]−1
像埃筛一样枚举,总复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2000;
const int mod = 1e9+7;
typedef long long ll;
class EraseToGCD{
public:
ll pw(ll x,ll y){
ll ret = 1;
while(y){
if(y&1)ret=(ret*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ret;
}
ll f[MAXN];
int countWays(vector <int> S, int goal){
memset(f,0,sizeof f);
for(int i=0;i<(int)S.size();i++){
f[S[i]]++;
}
for(int i=1;i<2000;i++){
for(int j=i*2;j<2000;j+=i){
f[i] += f[j];
}
}
// cout<<f[6]<<endl;
for(int i=1;i<2000;i++){
f[i]=pw(2,f[i]);
f[i]--;
if(f[i]<0)
f[i]+=mod;
}//cerr<<"here"<<endl;
for(int i=1999;i>0;i--){
for(int j=i*2;j<2000;j+=i){
f[i] -= f[j];
f[i]%=mod;
if(f[i]<0)
f[i]=(f[i]+mod)%mod;
}
}
return f[goal];
}
};
/*
int n=5,data[]={0,6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 15, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,0},g=6;
vector<int> arr;
int main(){
for(int i=1;data[i]!=0;i++)
arr.push_back(data[i]);
EraseToGCD t;
cout<<t.countWays(arr,g);
return 0;
}*/
PS
当然可以反演啦。
设
f
[
i
]
f[i]
f[i]为答案,S为枚举的集合
则
f
[
i
]
=
∑
S
[
g
c
d
{
S
}
=
=
i
]
f[i]=\sum_{S}[gcd{\{S\}} ==i]
f[i]=S∑[gcd{S}==i]
令
S
‘
S`
S‘为
S
S
S中的每个元素除以
i
i
i则
f
[
i
]
=
∑
S
‘
[
g
c
d
{
S
‘
}
=
=
1
]
f[i]=\sum_{S`}[gcd\{S`\}==1]
f[i]=S‘∑[gcd{S‘}==1]
然后大力反演
f
[
i
]
=
∑
S
‘
∑
d
∣
g
c
d
{
S
‘
}
μ
(
d
)
f[i]=\sum _{S`}\sum_{d|gcd{\{S`\}}}\mu(d)
f[i]=S‘∑d∣gcd{S‘}∑μ(d)
参考上面的
g
[
i
]
g[i]
g[i]的定义
则
f
[
i
]
=
∑
d
μ
(
d
)
∗
g
(
i
∗
d
)
f[i]=\sum_{d}\mu(d)*g(i*d)
f[i]=d∑μ(d)∗g(i∗d)
变换一下枚举元素
f
[
i
]
=
∑
i
∣
j
μ
(
j
/
i
)
∗
g
(
j
)
f[i]=\sum_{i|j}\mu(j/i)*g(j)
f[i]=i∣j∑μ(j/i)∗g(j)
和上面一样求
g
[
i
]
g[i]
g[i]就好了。
然而太懒了,没写代码。