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]为答案,即gcdgcdgcd为iii的组合有多少个,这个东西不太好求。
根据套路,要大力容斥。
设g[i]g[i]g[i]为gcdgcdgcd为iii的倍数的组合的个数
那么有
f[i]=g[i]−∑i∣d且i!=dg[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]为数字为iii的数字有多少个,h[i]h[i]h[i]为数字为iii的倍数的数字有多少个。
那么有h[i]=∑i∣da[d]h[i]=\sum_{i|d}a[d]h[i]=i∣d∑a[d]
这样就有g[i]=2h[i]−1g[i]=2^{h[i]}-1g[i]=2h[i]−1
像埃筛一样枚举,总复杂度为O(nlogn)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[gcd{S}==i]f[i]=\sum_{S}[gcd{\{S\}} ==i]f[i]=S∑[gcd{S}==i]
令S‘S`S‘为SSS中的每个元素除以iii则
f[i]=∑S‘[gcd{S‘}==1]f[i]=\sum_{S`}[gcd\{S`\}==1]f[i]=S‘∑[gcd{S‘}==1]
然后大力反演
f[i]=∑S‘∑d∣gcd{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]就好了。
然而太懒了,没写代码。