https://codeforces.com/gym/104396
E. LCM Plus GCD
题意
给定 x,k,求满足条件的 (a1,a2,⋯,ak) 的个数。
- a1,a2,⋯,ak 各不相同。
- gcd(a1,a2,⋯,ak)+lcm(a1,a2,⋯,ak)=x。
结果对 109+7 取模。
数据范围:1≤x,k≤109。
题解
设 gcd(a1,a2,⋯,ak)=g,记 lcm(a1,a2,⋯,ak)=a×g。则 (1+a)×g=x。枚举 g,令 ai′=gai,则 gcd(a1′,a2′,⋯,ak′)=1,lcm(a1′,a2′,⋯,ak′)=a。对 a 和 ai 做质因数分解,即 a=j=1∏mpjbj,ai=j=1∏mpjcij。那么,每个 cij 的取值一定在 [0,bj] 之间,同时,对每个 pj 有 min{cij}=0,max{cij}=bj。我们考虑容斥,一共有 2m 个约束,每个 pj 对应两个约束。一般地,每个 pj 有 (1+bj) 的贡献,但是如果它违反了一个约束,那么贡献要减少 1(因为 0 或 bj 将无法取到),违反两个就减少 2。然后把每个 pj 的贡献相乘,就是总的取值可能,从中选 k 个就可以了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int p=1e9+7; const int N=1e6+5; int x,k; ll fac[N],ifac[N]; void init() { fac[0]=1; for(int i=1;i<N;i++) fac[i]=i*fac[i-1]%p; ifac[0]=ifac[1]=1; for(int i=2;i<N;i++) ifac[i]=(p-p/i)*ifac[p%i]%p; for(int i=2;i<N;i++) ifac[i]=ifac[i]*ifac[i-1]%p; } ll C(int n,int m) { if(n<m) return 0; return fac[n]*ifac[m]%p*ifac[n-m]%p; } ll solve(int g) { int a=x/g-1; if(a==0) return 0; vector<pii> fac; for(int i=2;i*i<=a;i++) if(a%i==0) { int cnt=0; while(a%i==0) { cnt++; a/=i; } fac.push_back({i,cnt}); } if(a>1) fac.push_back({a,1}); int n=(int)fac.size(); ll sum=0; for(int i=0;i<(1<<n);i++) for(int j=0;j<(1<<n);j++) { int op=1,res=1; for(int k=0;k<n;k++) { int v=fac[k].second+1; if(i>>k&1) { op*=-1; v--; } if(j>>k&1) { op*=-1; v--; } res*=v; } sum=(sum+C(res,k)*op+p)%p; } return sum; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); init(); cin>>x>>k; ll ans=0; for(int i=1;i*i<=x;i++) if(x%i==0) { ans=(ans+solve(i))%p; if(i*i!=x) ans=(ans+solve(x/i))%p; } cout<<ans<<'\n'; return 0; }
|